View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0002215 | ardour | bugs | public | 2008-04-23 13:52 | 2012-01-10 18:00 |
| Reporter | colinf | Assigned To | paul | ||
| Priority | normal | Severity | minor | Reproducibility | always |
| Status | closed | Resolution | fixed | ||
| Product Version | SVN/2.0-ongoing | ||||
| Summary | 0002215: "Remove" in region context menu always removes topmost region when clicking on overlapping regions | ||||
| Description | When you right-click on an area containing two or more overlapping regions, "Remove" in the region sub-menus will always remove the topmost region, whichever sub-menu you chose it from. | ||||
| Additional Information | I've attached a patch which is my attempt to fix this, but it could certainly do with someone who understands C++ & boost looking at it to see whether it really makes sense. Also, from looking at the code, I think that "Add/Remove region sync point" suffers from the same bug, but I've neither tested nor tried to correct this. | ||||
| Tags | No tags attached. | ||||
|
2008-04-23 13:52
|
remove-chosen-region.patch (4,546 bytes)
Index: gtk2_ardour/editor_ops.cc
===================================================================
--- gtk2_ardour/editor_ops.cc (revision 3279)
+++ gtk2_ardour/editor_ops.cc (working copy)
@@ -195,6 +195,61 @@
}
void
+Editor::remove_region ()
+{
+
+ RegionSelection rs;
+ get_regions_for_action (rs);
+
+ if (!session) {
+ return;
+ }
+
+ if (rs.empty()) {
+ cerr << "rs.empty()" << endl;
+ return;
+ }
+
+ begin_reversible_command (_("remove region"));
+
+ list<boost::shared_ptr<Region> > regions_to_remove;
+
+ 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.
+
+ // I have no idea if this is good or right: I really ought to
+ // read up on boost and the standard c++ libs before trying
+ // stuff like this. however, it seems consistent with the
+ // rest of this file, and seems to work. XXX colinf.
+
+ regions_to_remove.push_back ((*i)->region());
+ }
+
+ for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
+ boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
+ if (!playlist) {
+ // is this check necessary?
+ cerr << "(*i)->region()->playlist() is NULL!" << endl;
+ continue;
+ }
+
+ XMLNode &before = playlist->get_state();
+ playlist->remove_region (*rl);
+ XMLNode &after = playlist->get_state();
+ session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
+ }
+ commit_reversible_command ();
+}
+
+#if 0
+void
Editor::destroy_clicked_region ()
{
uint32_t selected = selection->regions.size();
@@ -236,6 +291,7 @@
session->destroy_regions (r);
}
}
+#endif
boost::shared_ptr<Region>
Editor::select_region_for_operation (int dir, TimeAxisView **tv)
@@ -3099,6 +3155,7 @@
void
Editor::remove_region_sync ()
{
+ // XXX shouldn't this use get_regions_for_action(rs) too?
if (clicked_regionview) {
boost::shared_ptr<Region> region (clicked_regionview->region());
begin_reversible_command (_("remove sync"));
@@ -4396,6 +4453,7 @@
void
Editor::external_edit_region ()
{
+ // XXX shouldn't this use get_regions_for_action(rs) too?
if (!clicked_regionview) {
return;
}
Index: gtk2_ardour/editor.h
===================================================================
--- gtk2_ardour/editor.h (revision 3279)
+++ gtk2_ardour/editor.h (working copy)
@@ -995,8 +995,11 @@
void align_selection_relative (ARDOUR::RegionPoint point, nframes_t position, const RegionSelection&);
void align_region (boost::shared_ptr<ARDOUR::Region>, ARDOUR::RegionPoint point, nframes_t position);
void align_region_internal (boost::shared_ptr<ARDOUR::Region>, ARDOUR::RegionPoint point, nframes_t position);
+ void remove_region ();
void remove_clicked_region ();
+#if 0
void destroy_clicked_region ();
+#endif
void edit_region ();
void rename_region ();
void duplicate_some_regions (RegionSelection&, float times);
Index: gtk2_ardour/editor_selection.cc
===================================================================
--- gtk2_ardour/editor_selection.cc (revision 3279)
+++ gtk2_ardour/editor_selection.cc (working copy)
@@ -721,9 +721,11 @@
*/
if (selection->regions.size() > 1) {
- return true;
+ // return true;
}
+ cerr << "selection->regions.size() = " << selection->regions.size() << endl;
+
begin_reversible_command (_("set selected regions"));
selection->set (rv);
Index: gtk2_ardour/editor.cc
===================================================================
--- gtk2_ardour/editor.cc (revision 3279)
+++ gtk2_ardour/editor.cc (working copy)
@@ -1933,7 +1933,7 @@
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.
|
|
2008-05-01 17:21
|
region-context-menu-3300.patch (11,130 bytes)
Index: gtk2_ardour/editor_ops.cc
===================================================================
--- gtk2_ardour/editor_ops.cc (revision 3300)
+++ gtk2_ardour/editor_ops.cc (working copy)
@@ -196,6 +196,56 @@
}
void
+Editor::remove_region ()
+{
+
+ RegionSelection rs;
+ get_regions_for_action (rs);
+
+ if (!session) {
+ return;
+ }
+
+ if (rs.empty()) {
+ cerr << "rs.empty()" << endl;
+ return;
+ }
+
+ begin_reversible_command (_("remove region"));
+
+ list<boost::shared_ptr<Region> > regions_to_remove;
+
+ 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<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
+ boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
+ if (!playlist) {
+ // is this check necessary?
+ cerr << "(*i)->region()->playlist() is NULL!" << endl;
+ continue;
+ }
+
+ XMLNode &before = playlist->get_state();
+ playlist->remove_region (*rl);
+ XMLNode &after = playlist->get_state();
+ session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
+ }
+ commit_reversible_command ();
+}
+
+#if 0
+void
Editor::destroy_clicked_region ()
{
uint32_t selected = selection->regions.size();
@@ -237,6 +287,7 @@
session->destroy_regions (r);
}
}
+#endif
boost::shared_ptr<Region>
Editor::select_region_for_operation (int dir, TimeAxisView **tv)
@@ -3136,15 +3187,23 @@
void
Editor::remove_region_sync ()
{
- if (clicked_regionview) {
- boost::shared_ptr<Region> 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<Playlist>(*(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<Playlist>(*((*i)->region()->playlist()), &before, &after));
+ }
+ commit_reversible_command ();
}
void
@@ -4433,6 +4492,7 @@
void
Editor::external_edit_region ()
{
+ // XXX shouldn't this use get_regions_for_action(rs) too?
if (!clicked_regionview) {
return;
}
Index: gtk2_ardour/editor.cc
===================================================================
--- gtk2_ardour/editor.cc (revision 3300)
+++ gtk2_ardour/editor.cc (working copy)
@@ -1599,8 +1599,16 @@
if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) {
Playlist::RegionList* regions = pl->regions_at ((nframes_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<Region> 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;
}
@@ -1638,10 +1646,17 @@
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<Region> 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;
}
}
@@ -1772,18 +1787,27 @@
boost::shared_ptr<AudioRegion> ar;
+ cerr << "add_region_context_items()" << endl;
+
if (region) {
ar = boost::dynamic_pointer_cast<AudioRegion> (region);
- }
- /* when this particular menu pops up, make the relevant region
- become selected.
- */
+ /* 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>(region)));
+ region_menu->signal_map_event().connect (
+ bind (
+ mem_fun(*this, &Editor::set_selected_regionview_from_map_event),
+ sv,
+ boost::weak_ptr<Region>(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 (_("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());
@@ -1803,49 +1827,51 @@
sigc::connection fooc;
- items.push_back (CheckMenuElem (_("Lock")));
- CheckMenuItem* region_lock_item = static_cast<CheckMenuItem*>(&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<CheckMenuItem*>(&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<CheckMenuItem*>(&items.back());
+ items.push_back (CheckMenuElem (_("Glue to Bars&Beats")));
+ CheckMenuItem* bbt_glue_item = static_cast<CheckMenuItem*>(&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<CheckMenuItem*>(&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<CheckMenuItem*>(&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<CheckMenuItem*>(&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<CheckMenuItem*>(&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);
}
@@ -1933,7 +1959,7 @@
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.
@@ -1944,7 +1970,7 @@
*/
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, "__");
Index: gtk2_ardour/editor.h
===================================================================
--- gtk2_ardour/editor.h (revision 3300)
+++ gtk2_ardour/editor.h (working copy)
@@ -995,8 +995,11 @@
void align_selection_relative (ARDOUR::RegionPoint point, nframes_t position, const RegionSelection&);
void align_region (boost::shared_ptr<ARDOUR::Region>, ARDOUR::RegionPoint point, nframes_t position);
void align_region_internal (boost::shared_ptr<ARDOUR::Region>, ARDOUR::RegionPoint point, nframes_t position);
+ void remove_region ();
void remove_clicked_region ();
+#if 0
void destroy_clicked_region ();
+#endif
void edit_region ();
void rename_region ();
void duplicate_some_regions (RegionSelection&, float times);
|
|
|
And here's a version of the patch (region-context-menu-3300.patch) which does correct the behaviour of "Remove region sync point" ("Add region sync point" was correct before). It also tries to behave better if multiple regions are selected: in that case, it will simply create one context menu, titled "Selected regions", instead of a separate sub-menu for each region at that point, and the items in that menu will affect all the selected regions. |
|
2008-05-01 19:55
|
region-context-menu-single-regions.patch (4,829 bytes)
Index: gtk2_ardour/editor_ops.cc
===================================================================
--- gtk2_ardour/editor_ops.cc (revision 3302)
+++ gtk2_ardour/editor_ops.cc (working copy)
@@ -196,6 +196,55 @@
}
void
+Editor::remove_region ()
+{
+
+ RegionSelection rs;
+ get_regions_for_action (rs);
+
+ if (!session) {
+ return;
+ }
+
+ if (rs.empty()) {
+ cerr << "rs.empty()" << endl;
+ return;
+ }
+
+ begin_reversible_command (_("remove region"));
+
+ list<boost::shared_ptr<Region> > regions_to_remove;
+
+ 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<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
+ boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
+ if (!playlist) {
+ // is this check necessary?
+ cerr << "(*i)->region()->playlist() is NULL!" << endl;
+ continue;
+ }
+
+ XMLNode &before = playlist->get_state();
+ playlist->remove_region (*rl);
+ XMLNode &after = playlist->get_state();
+ session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
+ }
+ commit_reversible_command ();
+}
+
+void
Editor::destroy_clicked_region ()
{
uint32_t selected = selection->regions.size();
@@ -3136,15 +3185,23 @@
void
Editor::remove_region_sync ()
{
- if (clicked_regionview) {
- boost::shared_ptr<Region> 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<Playlist>(*(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<Playlist>(*((*i)->region()->playlist()), &before, &after));
+ }
+ commit_reversible_command ();
}
void
@@ -4433,6 +4490,7 @@
void
Editor::external_edit_region ()
{
+ // XXX shouldn't this use get_regions_for_action(rs) too?
if (!clicked_regionview) {
return;
}
Index: gtk2_ardour/editor.cc
===================================================================
--- gtk2_ardour/editor.cc (revision 3302)
+++ gtk2_ardour/editor.cc (working copy)
@@ -1933,7 +1933,7 @@
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.
Index: gtk2_ardour/editor_selection.cc
===================================================================
--- gtk2_ardour/editor_selection.cc (revision 3302)
+++ gtk2_ardour/editor_selection.cc (working copy)
@@ -716,14 +716,6 @@
return true;
}
- /* don't reset the selection if its something other than
- a single other region.
- */
-
- if (selection->regions.size() > 1) {
- return true;
- }
-
begin_reversible_command (_("set selected regions"));
selection->set (rv);
Index: gtk2_ardour/editor.h
===================================================================
--- gtk2_ardour/editor.h (revision 3302)
+++ gtk2_ardour/editor.h (working copy)
@@ -995,6 +995,7 @@
void align_selection_relative (ARDOUR::RegionPoint point, nframes_t position, const RegionSelection&);
void align_region (boost::shared_ptr<ARDOUR::Region>, ARDOUR::RegionPoint point, nframes_t position);
void align_region_internal (boost::shared_ptr<ARDOUR::Region>, ARDOUR::RegionPoint point, nframes_t position);
+ void remove_region ();
void remove_clicked_region ();
void destroy_clicked_region ();
void edit_region ();
|
|
|
Here (region-context-menu-single-regions.patch) is a less intrusive version, that won't let the region context menus work on multiple region selections, but always forces the selection to a single region when the context menu pops up, regardless of what was selected before. |
|
|
second patch applied and committed. works very nicely. great stuff. |
|
|
Closing my old issues: this is long since fixed. |
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 2008-04-23 13:52 | colinf | New Issue | |
| 2008-04-23 13:52 | colinf | File Added: remove-chosen-region.patch | |
| 2008-05-01 17:21 | colinf | File Added: region-context-menu-3300.patch | |
| 2008-05-01 17:28 | colinf | Note Added: 0004912 | |
| 2008-05-01 19:55 | colinf | File Added: region-context-menu-single-regions.patch | |
| 2008-05-01 19:56 | colinf | Note Added: 0004914 | |
| 2008-06-18 22:38 | paul | cost | => 0.00 |
| 2008-06-18 22:38 | paul | Status | new => resolved |
| 2008-06-18 22:38 | paul | Resolution | open => fixed |
| 2008-06-18 22:38 | paul | Assigned To | => paul |
| 2008-06-18 22:38 | paul | Note Added: 0005054 | |
| 2012-01-10 18:00 | colinf | Note Added: 0012537 | |
| 2012-01-10 18:00 | colinf | Status | resolved => closed |