Re-work main right-click context menu to operate on the selection, and remove some confusion about what region(s) will be affected by menu selections.

git-svn-id: svn://localhost/ardour2/trunk@1831 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Carl Hetherington 2007-05-10 11:53:35 +00:00
parent 4342f2aeb0
commit aa3bb18b17
13 changed files with 484 additions and 675 deletions

View File

@ -292,9 +292,7 @@ Editor::Editor ()
new_transport_marker_menu = 0;
editor_mixer_strip_width = Wide;
show_editor_mixer_when_tracks_arrive = false;
region_edit_menu_split_item = 0;
temp_location = 0;
region_edit_menu_split_multichannel_item = 0;
leftmost_frame = 0;
ignore_mouse_mode_toggle = false;
current_stepping_trackview = 0;
@ -1217,6 +1215,7 @@ Editor::build_cursors ()
timebar_cursor = new Gdk::Cursor(LEFT_PTR);
}
/** Pop up a context menu for when the user clicks on a fade in or fade out */
void
Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
{
@ -1278,179 +1277,28 @@ Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* i
fade_context_menu.popup (button, time);
}
/* Pop up the general track context menu for when the user clicks pretty much anywhere in a track or bus */
void
Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection, nframes_t frame)
Editor::popup_track_context_menu (int button, int32_t time, nframes_t frame)
{
using namespace Menu_Helpers;
Menu* (Editor::*build_menu_function)(nframes_t);
Menu *menu;
switch (item_type) {
case RegionItem:
case RegionViewName:
case RegionViewNameHighlight:
if (with_selection) {
build_menu_function = &Editor::build_track_selection_context_menu;
} else {
build_menu_function = &Editor::build_track_region_context_menu;
}
break;
case SelectionItem:
if (with_selection) {
build_menu_function = &Editor::build_track_selection_context_menu;
} else {
build_menu_function = &Editor::build_track_context_menu;
}
break;
case CrossfadeViewItem:
build_menu_function = &Editor::build_track_crossfade_context_menu;
break;
case StreamItem:
if (clicked_routeview->is_track()) {
build_menu_function = &Editor::build_track_context_menu;
} else {
build_menu_function = &Editor::build_track_bus_context_menu;
}
break;
default:
/* probably shouldn't happen but if it does, we don't care */
return;
}
menu = (this->*build_menu_function)(frame);
menu->set_name ("ArdourContextMenu");
/* now handle specific situations */
switch (item_type) {
case RegionItem:
case RegionViewName:
case RegionViewNameHighlight:
if (!with_selection) {
if (region_edit_menu_split_item) {
if (clicked_regionview && clicked_regionview->region()->covers (edit_cursor->current_frame)) {
ActionManager::set_sensitive (ActionManager::edit_cursor_in_region_sensitive_actions, true);
} else {
ActionManager::set_sensitive (ActionManager::edit_cursor_in_region_sensitive_actions, false);
}
}
/*
if (region_edit_menu_split_multichannel_item) {
if (clicked_regionview && clicked_regionview->region().n_channels() > 1) {
// GTK2FIX find the action, change its sensitivity
// region_edit_menu_split_multichannel_item->set_sensitive (true);
} else {
// GTK2FIX see above
// region_edit_menu_split_multichannel_item->set_sensitive (false);
}
}*/
}
break;
case SelectionItem:
break;
case CrossfadeViewItem:
break;
case StreamItem:
break;
default:
/* probably shouldn't happen but if it does, we don't care */
return;
}
if (clicked_routeview && clicked_routeview->audio_track()) {
/* Bounce to disk */
using namespace Menu_Helpers;
MenuList& edit_items = menu->items();
edit_items.push_back (SeparatorElem());
switch (clicked_routeview->audio_track()->freeze_state()) {
case AudioTrack::NoFreeze:
edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
break;
case AudioTrack::Frozen:
edit_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_route)));
break;
case AudioTrack::UnFrozen:
edit_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_route)));
break;
}
}
menu->popup (button, time);
build_track_context_menu (frame)->popup (button, time);
}
Menu*
Editor::build_track_context_menu (nframes_t ignored)
Editor::build_track_context_menu (nframes_t frame)
{
using namespace Menu_Helpers;
MenuList& edit_items = track_context_menu.items();
Menu* menu = manage (new Menu);
MenuList& edit_items = menu->items();
edit_items.clear();
add_dstream_context_items (edit_items);
return &track_context_menu;
}
Menu*
Editor::build_track_bus_context_menu (nframes_t ignored)
{
using namespace Menu_Helpers;
MenuList& edit_items = track_context_menu.items();
edit_items.clear();
add_bus_context_items (edit_items);
return &track_context_menu;
}
Menu*
Editor::build_track_region_context_menu (nframes_t frame)
{
using namespace Menu_Helpers;
MenuList& edit_items = track_region_context_menu.items();
edit_items.clear();
AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_axisview);
if (atv) {
boost::shared_ptr<Diskstream> ds;
boost::shared_ptr<Playlist> pl;
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);
}
delete regions;
}
}
add_dstream_context_items (edit_items);
return &track_region_context_menu;
}
Menu*
Editor::build_track_crossfade_context_menu (nframes_t frame)
{
using namespace Menu_Helpers;
MenuList& edit_items = track_crossfade_context_menu.items();
edit_items.clear ();
/* Build the general `track' context menu, adding what is appropriate given
the current selection */
/* XXX: currently crossfades can't be selected, so we can't use the selection
to decide which crossfades to mention in the menu. I believe this will
change at some point. For now we have to use clicked_trackview to decide. */
AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_axisview);
if (atv) {
@ -1460,9 +1308,7 @@ Editor::build_track_crossfade_context_menu (nframes_t frame)
if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
Playlist::RegionList* regions = pl->regions_at (frame);
AudioPlaylist::Crossfades xfades;
apl->crossfades_at (frame, xfades);
bool many = xfades.size() > 1;
@ -1470,18 +1316,24 @@ Editor::build_track_crossfade_context_menu (nframes_t frame)
for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
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);
}
delete regions;
}
}
if (!selection->time.empty()) {
add_selection_context_items (edit_items);
}
add_dstream_context_items (edit_items);
if (!selection->regions.empty()) {
add_region_context_items (edit_items);
}
return &track_crossfade_context_menu;
if (!selection->tracks.empty()) {
add_bus_or_audio_track_context_items (edit_items);
}
menu->set_name ("ArdourContextMenu");
return menu;
}
#ifdef FFT_ANALYSIS
@ -1523,20 +1375,9 @@ Editor::analyze_range_selection()
#endif /* FFT_ANALYSIS */
Menu*
Editor::build_track_selection_context_menu (nframes_t ignored)
{
using namespace Menu_Helpers;
MenuList& edit_items = track_selection_context_menu.items();
edit_items.clear ();
add_selection_context_items (edit_items);
add_dstream_context_items (edit_items);
return &track_selection_context_menu;
}
/** Add context menu items relevant to crossfades.
* @param edit_items List to add the items to.
*/
void
Editor::add_crossfade_context_items (AudioStreamView* view, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
{
@ -1594,36 +1435,48 @@ Editor::xfade_edit_right_region ()
}
}
/** Add an element to a menu, settings its sensitivity.
* @param m Menu to add to.
* @param e Element to add.
* @param s true to make sensitive, false to make insensitive
*/
void
Editor::add_region_context_items (AudioStreamView* sv, boost::shared_ptr<Region> region, Menu_Helpers::MenuList& edit_items)
Editor::add_item_with_sensitivity (Menu_Helpers::MenuList& m, Menu_Helpers::MenuElem e, bool s) const
{
m.push_back (e);
if (!s) {
m.back().set_sensitive (false);
}
}
/** Add context menu items relevant to regions.
* @param edit_items List to add the items to.
*/
void
Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items)
{
using namespace Menu_Helpers;
Menu *region_menu = manage (new Menu);
MenuList& items = region_menu->items();
Menu *region_menu = manage (new Menu);
MenuList& items = region_menu->items();
region_menu->set_name ("ArdourContextMenu");
boost::shared_ptr<AudioRegion> ar;
if (region) {
ar = boost::dynamic_pointer_cast<AudioRegion> (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>(region)));
items.push_back (MenuElem (_("Popup region editor"), mem_fun(*this, &Editor::edit_region)));
items.push_back (MenuElem (_("Edit..."), 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());
items.push_back (MenuElem (_("Define sync point"), mem_fun(*this, &Editor::set_region_sync_from_edit_cursor)));
items.push_back (MenuElem (_("Remove sync point"), mem_fun(*this, &Editor::remove_region_sync)));
items.push_back (SeparatorElem());
items.push_back (MenuElem (_("Audition"), mem_fun(*this, &Editor::audition_selected_region)));
items.push_back (MenuElem (_("Export"), mem_fun(*this, &Editor::export_region)));
Menu* sync_point_menu = manage (new Menu);
MenuList& sync_point_items = sync_point_menu->items();
sync_point_menu->set_name("ArdourContextMenu");
sync_point_items.push_back (MenuElem (_("Define"), mem_fun(*this, &Editor::set_region_sync_from_edit_cursor)));
sync_point_items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_region_sync)));
items.push_back (MenuElem (_("Sync points"), *sync_point_menu));
add_item_with_sensitivity (items, MenuElem (_("Audition"), mem_fun(*this, &Editor::audition_selected_region)), selection->regions.size() == 1);
add_item_with_sensitivity (items, MenuElem (_("Export"), mem_fun(*this, &Editor::export_region)), selection->regions.size() == 1);
items.push_back (MenuElem (_("Bounce"), mem_fun(*this, &Editor::bounce_region_selection)));
#ifdef FFT_ANALYSIS
@ -1632,83 +1485,59 @@ Editor::add_region_context_items (AudioStreamView* sv, boost::shared_ptr<Region>
items.push_back (SeparatorElem());
sigc::connection fooc;
items.push_back (MenuElem (_("Lock"), bind (mem_fun (*this, &Editor::set_region_lock), true)));
items.push_back (MenuElem (_("Unlock"), bind (mem_fun (*this, &Editor::set_region_lock), false)));
items.push_back (MenuElem (_("Mute"), bind (mem_fun (*this, &Editor::set_region_mute), true)));
items.push_back (MenuElem (_("Unmute"), bind (mem_fun (*this, &Editor::set_region_mute), false)));
items.push_back (MenuElem (_("Opaque"), bind (mem_fun (*this, &Editor::set_region_opaque), true)));
items.push_back (MenuElem (_("Transparent"), bind (mem_fun (*this, &Editor::set_region_opaque), false)));
items.push_back (CheckMenuElem (_("Lock")));
region_lock_item = static_cast<CheckMenuItem*>(&items.back());
fooc = region_lock_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_lock));
if (region->locked()) {
fooc.block (true);
region_lock_item->set_active();
fooc.block (false);
}
items.push_back (CheckMenuElem (_("Mute")));
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);
/* We allow "Original position" if at least one region is not at its
natural position */
RegionSelection::iterator i = selection->regions.begin();
while (i != selection->regions.end() && (*i)->region()->at_natural_position() == true) {
++i;
}
items.push_back (CheckMenuElem (_("Opaque")));
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()) {
items.back().set_sensitive (false);
}
add_item_with_sensitivity (items, MenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize)), i != selection->regions.end());
items.push_back (SeparatorElem());
if (ar) {
RegionView* rv = sv->find_view (ar);
AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
items.push_back (MenuElem (_("Reset Envelope"), mem_fun(*this, &Editor::reset_region_gain_envelopes)));
items.push_back (CheckMenuElem (_("Envelope Visible")));
region_envelope_visible_item = static_cast<CheckMenuItem*> (&items.back());
fooc = region_envelope_visible_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_visibility));
if (arv->envelope_visible()) {
fooc.block (true);
region_envelope_visible_item->set_active (true);
fooc.block (false);
}
items.push_back (CheckMenuElem (_("Envelope Active")));
region_envelope_active_item = static_cast<CheckMenuItem*> (&items.back());
fooc = region_envelope_active_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_gain_envelope_active));
if (ar->envelope_active()) {
fooc.block (true);
region_envelope_active_item->set_active (true);
fooc.block (false);
}
items.push_back (SeparatorElem());
if (ar->scale_amplitude() != 1.0f) {
items.push_back (MenuElem (_("DeNormalize"), mem_fun(*this, &Editor::denormalize_region)));
} else {
items.push_back (MenuElem (_("Normalize"), mem_fun(*this, &Editor::normalize_region)));
}
/* Find out if we have a selected audio region */
i = selection->regions.begin();
while (i != selection->regions.end() && boost::dynamic_pointer_cast<AudioRegion>((*i)->region()) == 0) {
++i;
}
items.push_back (MenuElem (_("Reverse"), mem_fun(*this, &Editor::reverse_region)));
bool const have_selected_audio_region = (i != selection->regions.end());
if (have_selected_audio_region) {
Menu* envelopes_menu = manage (new Menu);
MenuList& envelopes_items = envelopes_menu->items();
envelopes_menu->set_name ("ArdourContextMenu");
envelopes_items.push_back (MenuElem (_("Reset"), mem_fun(*this, &Editor::reset_region_gain_envelopes)));
envelopes_items.push_back (MenuElem (_("Visible"), bind (mem_fun (*this, &Editor::set_gain_envelope_visibility), true)));
envelopes_items.push_back (MenuElem (_("Invisible"), bind (mem_fun (*this, &Editor::set_gain_envelope_visibility), false)));
envelopes_items.push_back (MenuElem (_("Active"), bind (mem_fun (*this, &Editor::set_gain_envelope_active), true)));
envelopes_items.push_back (MenuElem (_("Inactive"), bind (mem_fun (*this, &Editor::set_gain_envelope_active), false)));
items.push_back (MenuElem (_("Envelopes"), *envelopes_menu));
items.push_back (MenuElem (_("Denormalize"), mem_fun (*this, &Editor::denormalize_regions)));
items.push_back (MenuElem (_("Normalize"), mem_fun (*this, &Editor::normalize_regions)));
}
items.push_back (MenuElem (_("Reverse"), mem_fun(*this, &Editor::reverse_regions)));
items.push_back (SeparatorElem());
/* range related stuff */
items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_audio_region)));
items.push_back (MenuElem (_("Set Range Selection"), mem_fun (*this, &Editor::set_selection_from_audio_region)));
add_item_with_sensitivity (items, MenuElem (_("Add range markers"), mem_fun (*this, &Editor::add_location_from_audio_region)), selection->regions.size() == 1);
add_item_with_sensitivity (items, MenuElem (_("Set range selection"), mem_fun (*this, &Editor::set_selection_from_audio_region)), selection->regions.size() == 1);
items.push_back (SeparatorElem());
/* Nudge region */
@ -1717,13 +1546,12 @@ Editor::add_region_context_items (AudioStreamView* sv, boost::shared_ptr<Region>
MenuList& nudge_items = nudge_menu->items();
nudge_menu->set_name ("ArdourContextMenu");
nudge_items.push_back (MenuElem (_("Nudge fwd"), (bind (mem_fun(*this, &Editor::nudge_forward), false))));
nudge_items.push_back (MenuElem (_("Nudge bwd"), (bind (mem_fun(*this, &Editor::nudge_backward), false))));
nudge_items.push_back (MenuElem (_("Nudge fwd by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
nudge_items.push_back (MenuElem (_("Nudge bwd by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
nudge_items.push_back (MenuElem (_("Nudge forward"), (bind (mem_fun(*this, &Editor::nudge_forward), false))));
nudge_items.push_back (MenuElem (_("Nudge backward"), (bind (mem_fun(*this, &Editor::nudge_backward), false))));
nudge_items.push_back (MenuElem (_("Nudge forward by capture offset"), (mem_fun(*this, &Editor::nudge_forward_capture_offset))));
nudge_items.push_back (MenuElem (_("Nudge backward by capture offset"), (mem_fun(*this, &Editor::nudge_backward_capture_offset))));
items.push_back (MenuElem (_("Nudge"), *nudge_menu));
items.push_back (SeparatorElem());
Menu *trim_menu = manage (new Menu);
MenuList& trim_items = trim_menu->items();
@ -1733,39 +1561,24 @@ Editor::add_region_context_items (AudioStreamView* sv, boost::shared_ptr<Region>
trim_items.push_back (MenuElem (_("Edit cursor to end"), mem_fun(*this, &Editor::trim_region_to_edit_cursor)));
items.push_back (MenuElem (_("Trim"), *trim_menu));
items.push_back (SeparatorElem());
items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
region_edit_menu_split_item = &items.back();
items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
region_edit_menu_split_multichannel_item = &items.back();
items.push_back (MenuElem (_("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 (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_selected_regions)));
/* OK, stick the region submenu at the top of the list, and then add
the standard items.
*/
/* we have to hack up the region name because "_" has a special
meaning for menu titles.
*/
string::size_type pos = 0;
string menu_item_name = region->name();
while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
menu_item_name.replace (pos, 1, "__");
pos += 2;
}
string const menu_item_name = selection->regions.size() > 1 ? _("Regions") : _("Region");
edit_items.push_back (MenuElem (menu_item_name, *region_menu));
edit_items.push_back (SeparatorElem());
}
/** Add context menu items relevant to selection ranges.
* @param edit_items List to add the items to.
*/
void
Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
{
@ -1789,7 +1602,7 @@ Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
items.push_back (SeparatorElem());
items.push_back (MenuElem (_("Select all in range"), mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
items.push_back (SeparatorElem());
items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_selection)));
items.push_back (MenuElem (_("Add range markers"), mem_fun (*this, &Editor::add_location_from_selection)));
items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
items.push_back (SeparatorElem());
@ -1805,11 +1618,33 @@ Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
edit_items.push_back (SeparatorElem());
}
/** Add context menu items relevant to busses or audio tracks.
* @param edit_items List to add the items to.
*/
void
Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
Editor::add_bus_or_audio_track_context_items (Menu_Helpers::MenuList& edit_items)
{
using namespace Menu_Helpers;
/* We add every possible action here, and de-sensitize things
that aren't allowed. The sensitivity logic is a bit spread out;
on the one hand I'm using things like can_cut_copy (), which is
reasonably complicated and so perhaps better near the function that
it expresses sensitivity for, and on the other hand checks
in this function as well. You can't really have can_* for everything
or the number of methods would get silly. */
bool const one_selected_region = selection->regions.size() == 1;
/* Count the number of selected audio tracks */
int n_audio_tracks = 0;
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
RouteTimeAxisView const * r = dynamic_cast<RouteTimeAxisView*>(*i);
if (r && r->is_audio_track()) {
n_audio_tracks++;
}
}
/* Playback */
Menu *play_menu = manage (new Menu);
@ -1818,9 +1653,9 @@ Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
play_items.push_back (MenuElem (_("Play from edit cursor"), mem_fun(*this, &Editor::play_from_edit_cursor)));
play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
play_items.push_back (MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)));
play_items.push_back (SeparatorElem());
play_items.push_back (MenuElem (_("Loop Region"), mem_fun(*this, &Editor::loop_selected_region)));
add_item_with_sensitivity (play_items, MenuElem (_("Play region"), mem_fun(*this, &Editor::play_selected_region)), one_selected_region);
add_item_with_sensitivity (play_items, MenuElem (_("Loop region"), mem_fun(*this, &Editor::loop_selected_region)), one_selected_region);
edit_items.push_back (MenuElem (_("Play"), *play_menu));
@ -1829,21 +1664,33 @@ Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
Menu *select_menu = manage (new Menu);
MenuList& select_items = select_menu->items();
select_menu->set_name ("ArdourContextMenu");
string str = selection->tracks.size() == 1 ? _("Select all in track") : _("Select all in tracks");
select_items.push_back (MenuElem (str, bind (mem_fun(*this, &Editor::select_all_in_selected_tracks), Selection::Set)));
select_items.push_back (MenuElem (_("Select all"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
str = selection->tracks.size() == 1 ? _("Invert selection in track") : _("Invert selection in tracks");
select_items.push_back (MenuElem (str, mem_fun(*this, &Editor::invert_selection_in_selected_tracks)));
select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
select_items.push_back (MenuElem (_("Invert selection in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
select_items.push_back (SeparatorElem());
select_items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
select_items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
select_items.push_back (SeparatorElem());
if (n_audio_tracks) {
select_items.push_back (MenuElem (_("Set range to loop range"), mem_fun(*this, &Editor::set_selection_from_loop)));
select_items.push_back (MenuElem (_("Set range to punch range"), mem_fun(*this, &Editor::set_selection_from_punch)));
}
select_items.push_back (MenuElem (_("Select all after edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, true)));
select_items.push_back (MenuElem (_("Select all before edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, false)));
select_items.push_back (MenuElem (_("Select all after playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
select_items.push_back (MenuElem (_("Select all before playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
select_items.push_back (MenuElem (_("Select all between cursors"), bind (mem_fun(*this, &Editor::select_all_selectables_between_cursors), playhead_cursor, edit_cursor)));
select_items.push_back (SeparatorElem());
if (n_audio_tracks) {
select_items.push_back (MenuElem (_("Select all between cursors"), bind (mem_fun(*this, &Editor::select_all_selectables_between_cursors), playhead_cursor, edit_cursor)));
}
edit_items.push_back (MenuElem (_("Select"), *select_menu));
@ -1852,98 +1699,68 @@ Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
Menu *cutnpaste_menu = manage (new Menu);
MenuList& cutnpaste_items = cutnpaste_menu->items();
cutnpaste_menu->set_name ("ArdourContextMenu");
add_item_with_sensitivity (cutnpaste_items, MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)), can_cut_copy ());
cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
cutnpaste_items.push_back (MenuElem (_("Paste at edit cursor"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
cutnpaste_items.push_back (MenuElem (_("Paste at mouse"), mem_fun(*this, &Editor::mouse_paste)));
cutnpaste_items.push_back (SeparatorElem());
cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
cutnpaste_items.push_back (MenuElem (_("Align Relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
cutnpaste_items.push_back (SeparatorElem());
cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
add_item_with_sensitivity (cutnpaste_items, MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)), can_cut_copy ());
if (n_audio_tracks) {
cutnpaste_items.push_back (MenuElem (_("Paste at edit cursor"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
cutnpaste_items.push_back (MenuElem (_("Paste at mouse"), mem_fun(*this, &Editor::mouse_paste)));
cutnpaste_items.push_back (SeparatorElem());
cutnpaste_items.push_back (MenuElem (_("Align"), bind (mem_fun(*this, &Editor::align), ARDOUR::SyncPoint)));
cutnpaste_items.push_back (MenuElem (_("Align relative"), bind (mem_fun(*this, &Editor::align_relative), ARDOUR::SyncPoint)));
cutnpaste_items.push_back (MenuElem (_("Insert chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f)));
} else {
cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
}
edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
if (n_audio_tracks) {
/* Adding new material */
Menu *track_menu = manage (new Menu);
MenuList& track_items = track_menu->items();
track_menu->set_name ("ArdourContextMenu");
/* Adding new material */
edit_items.push_back (SeparatorElem());
edit_items.push_back (MenuElem (_("Insert Selected Region"), bind (mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
edit_items.push_back (MenuElem (_("Insert Existing Audio"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
add_item_with_sensitivity (track_items, MenuElem (_("Insert selected region"), bind (mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)), n_audio_tracks == 1);
add_item_with_sensitivity (track_items, MenuElem (_("Insert existing audio"), bind (mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)), n_audio_tracks == 1);
/* Nudge */
/* Nudge track */
Menu *nudge_menu = manage (new Menu());
MenuList& nudge_items = nudge_menu->items();
nudge_menu->set_name ("ArdourContextMenu");
Menu *nudge_menu = manage (new Menu());
MenuList& nudge_items = nudge_menu->items();
nudge_menu->set_name ("ArdourContextMenu");
edit_items.push_back (SeparatorElem());
nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
nudge_items.push_back (MenuElem (_("Nudge track after edit cursor fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
nudge_items.push_back (MenuElem (_("Nudge track after edit cursor bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
str = selection->tracks.size() == 1 ? _("Nudge track forward") : _("Nude tracks forward");
nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), false, true))));
edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
}
str = selection->tracks.size() == 1 ? _("Nudge track after edit cursor forward") : _("Nudge tracks after edit cursor forward");
nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), true, true))));
void
Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
{
using namespace Menu_Helpers;
str = selection->tracks.size() == 1 ? _("Nudge track backward") : _("Nudge tracks backward");
nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), false, false))));
/* Playback */
str = selection->tracks.size() == 1 ? _("Nudge track after edit cursor backward") : _("Nudge tracks after edit cursor backward");
nudge_items.push_back (MenuElem (str, (bind (mem_fun(*this, &Editor::nudge_selected_tracks), true, false))));
track_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
Menu *play_menu = manage (new Menu);
MenuList& play_items = play_menu->items();
play_menu->set_name ("ArdourContextMenu");
play_items.push_back (MenuElem (_("Play from edit cursor"), mem_fun(*this, &Editor::play_from_edit_cursor)));
play_items.push_back (MenuElem (_("Play from start"), mem_fun(*this, &Editor::play_from_start)));
edit_items.push_back (MenuElem (_("Play"), *play_menu));
/* Freeze */
track_items.push_back (MenuElem (_("Freeze"), mem_fun(*this, &Editor::freeze_routes)));
track_items.push_back (MenuElem (_("Unfreeze"), mem_fun(*this, &Editor::unfreeze_routes)));
/* Selection */
Menu *select_menu = manage (new Menu);
MenuList& select_items = select_menu->items();
select_menu->set_name ("ArdourContextMenu");
select_items.push_back (MenuElem (_("Select All in track"), bind (mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
select_items.push_back (MenuElem (_("Select All"), bind (mem_fun(*this, &Editor::select_all), Selection::Set)));
select_items.push_back (MenuElem (_("Invert selection in track"), mem_fun(*this, &Editor::invert_selection_in_track)));
select_items.push_back (MenuElem (_("Invert selection"), mem_fun(*this, &Editor::invert_selection)));
select_items.push_back (SeparatorElem());
select_items.push_back (MenuElem (_("Select all after edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, true)));
select_items.push_back (MenuElem (_("Select all before edit cursor"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), edit_cursor, false)));
select_items.push_back (MenuElem (_("Select all after playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
select_items.push_back (MenuElem (_("Select all before playhead"), bind (mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
edit_items.push_back (MenuElem (_("Select"), *select_menu));
/* Cut-n-Paste */
Menu *cutnpaste_menu = manage (new Menu);
MenuList& cutnpaste_items = cutnpaste_menu->items();
cutnpaste_menu->set_name ("ArdourContextMenu");
cutnpaste_items.push_back (MenuElem (_("Cut"), mem_fun(*this, &Editor::cut)));
cutnpaste_items.push_back (MenuElem (_("Copy"), mem_fun(*this, &Editor::copy)));
cutnpaste_items.push_back (MenuElem (_("Paste"), bind (mem_fun(*this, &Editor::paste), 1.0f)));
Menu *nudge_menu = manage (new Menu());
MenuList& nudge_items = nudge_menu->items();
nudge_menu->set_name ("ArdourContextMenu");
edit_items.push_back (SeparatorElem());
nudge_items.push_back (MenuElem (_("Nudge entire track fwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, true))));
nudge_items.push_back (MenuElem (_("Nudge track after edit cursor fwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, true))));
nudge_items.push_back (MenuElem (_("Nudge entire track bwd"), (bind (mem_fun(*this, &Editor::nudge_track), false, false))));
nudge_items.push_back (MenuElem (_("Nudge track after edit cursor bwd"), (bind (mem_fun(*this, &Editor::nudge_track), true, false))));
edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
str = selection->tracks.size() == 1 ? _("Track") : _("Tracks");
edit_items.push_back (MenuElem (str, *track_menu));
}
}
/* CURSOR SETTING AND MARKS AND STUFF */
@ -3460,15 +3277,9 @@ Editor::popup_snapshot_context_menu (int button, int32_t time, Glib::ustring sna
const bool modification_allowed = (session->snap_name() != snapshot_name && session->name() != snapshot_name);
items.push_back (MenuElem (_("Remove"), bind (mem_fun (*this, &Editor::remove_snapshot), snapshot_name)));
if (!modification_allowed) {
items.back().set_sensitive (false);
}
add_item_with_sensitivity (items, MenuElem (_("Remove"), bind (mem_fun (*this, &Editor::remove_snapshot), snapshot_name)), modification_allowed);
items.push_back (MenuElem (_("Rename"), bind (mem_fun (*this, &Editor::rename_snapshot), snapshot_name)));
if (!modification_allowed) {
items.back().set_sensitive (false);
}
add_item_with_sensitivity (items, MenuElem (_("Rename"), bind (mem_fun (*this, &Editor::rename_snapshot), snapshot_name)), modification_allowed);
snapshot_context_menu.popup (button, time);
}

View File

@ -140,7 +140,7 @@ class Editor : public PublicEditor
void set_mouse_mode (Editing::MouseMode, bool force=true);
void step_mouse_mode (bool next);
Editing::MouseMode current_mouse_mode () { return mouse_mode; }
Editing::MouseMode current_mouse_mode () const { return mouse_mode; }
void add_imageframe_time_axis(const std::string & track_name, void*) ;
void add_imageframe_marker_time_axis(const std::string & track_name, TimeAxisView* marked_track, void*) ;
@ -216,9 +216,9 @@ class Editor : public PublicEditor
bool extend_selection_to_track (TimeAxisView&);
void play_selection ();
void select_all_in_track (Selection::Operation op);
void select_all_in_selected_tracks (Selection::Operation op);
void select_all (Selection::Operation op);
void invert_selection_in_track ();
void invert_selection_in_selected_tracks ();
void invert_selection ();
/* tempo */
@ -412,7 +412,12 @@ class Editor : public PublicEditor
TimeAxisView* clicked_axisview;
RouteTimeAxisView* clicked_routeview;
/** The last RegionView that was clicked on, or 0 if the last click was not
* on a RegionView. This is set up by the canvas event handlers in
* editor_canvas_events.cc
*/
RegionView* clicked_regionview;
RegionView* latest_regionview;
uint32_t clicked_selection;
CrossfadeView* clicked_crossfadeview;
@ -446,32 +451,17 @@ class Editor : public PublicEditor
bool set_selected_regionview_from_click (bool press, Selection::Operation op = Selection::Set, bool no_track_remove=false);
void set_selected_regionview_from_region_list (boost::shared_ptr<ARDOUR::Region> region, Selection::Operation op = Selection::Set);
bool set_selected_regionview_from_map_event (GdkEventAny*, StreamView*, boost::weak_ptr<ARDOUR::Region>);
void collect_new_region_view (RegionView *);
Gtk::Menu track_context_menu;
Gtk::Menu track_region_context_menu;
Gtk::Menu track_selection_context_menu;
Gtk::Menu track_crossfade_context_menu;
Gtk::MenuItem* region_edit_menu_split_item;
Gtk::MenuItem* region_edit_menu_split_multichannel_item;
Gtk::Menu * track_region_edit_playlist_menu;
Gtk::Menu * track_edit_playlist_submenu;
Gtk::Menu * track_selection_edit_playlist_submenu;
void popup_track_context_menu (int, int, ItemType, bool, nframes_t);
void popup_track_context_menu (int, int, nframes_t);
Gtk::Menu* build_track_context_menu (nframes_t);
Gtk::Menu* build_track_bus_context_menu (nframes_t);
Gtk::Menu* build_track_region_context_menu (nframes_t frame);
Gtk::Menu* build_track_crossfade_context_menu (nframes_t);
Gtk::Menu* build_track_selection_context_menu (nframes_t);
void add_dstream_context_items (Gtk::Menu_Helpers::MenuList&);
void add_bus_context_items (Gtk::Menu_Helpers::MenuList&);
void add_region_context_items (AudioStreamView*, boost::shared_ptr<ARDOUR::Region>, Gtk::Menu_Helpers::MenuList&);
void add_bus_or_audio_track_context_items (Gtk::Menu_Helpers::MenuList&);
void add_region_context_items (Gtk::Menu_Helpers::MenuList&);
void add_crossfade_context_items (AudioStreamView*, boost::shared_ptr<ARDOUR::Crossfade>, Gtk::Menu_Helpers::MenuList&, bool many);
void add_selection_context_items (Gtk::Menu_Helpers::MenuList&);
void add_item_with_sensitivity (Gtk::Menu_Helpers::MenuList&, Gtk::Menu_Helpers::MenuElem, bool) const;
void handle_new_route (ARDOUR::Session::RouteList&);
void remove_route (TimeAxisView *);
bool route_removal;
@ -862,6 +852,7 @@ class Editor : public PublicEditor
list<boost::shared_ptr<ARDOUR::Region> > tmp_region_list;
void cut_copy (Editing::CutCopyOp);
bool can_cut_copy () const;
void cut_copy_points (Editing::CutCopyOp);
void cut_copy_regions (Editing::CutCopyOp);
void cut_copy_ranges (Editing::CutCopyOp);
@ -872,9 +863,9 @@ class Editor : public PublicEditor
/* EDITING OPERATIONS */
void reset_point_selection ();
void toggle_region_mute ();
void toggle_region_lock ();
void toggle_region_opaque ();
void set_region_mute (bool);
void set_region_lock (bool);
void set_region_opaque (bool);
void raise_region ();
void raise_region_to_top ();
void lower_region ();
@ -890,8 +881,8 @@ class Editor : public PublicEditor
void align_selection_relative (ARDOUR::RegionPoint point, nframes_t position);
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_selected_regions ();
void remove_clicked_region ();
void destroy_clicked_region ();
void edit_region ();
void duplicate_some_regions (RegionSelection&, float times);
void duplicate_selection (float times);
@ -901,9 +892,9 @@ class Editor : public PublicEditor
void audition_playlist_region_standalone (boost::shared_ptr<ARDOUR::Region>);
void audition_playlist_region_via_route (boost::shared_ptr<ARDOUR::Region>, ARDOUR::Route&);
void split_multichannel_region();
void reverse_region ();
void normalize_region ();
void denormalize_region ();
void reverse_regions ();
void normalize_regions ();
void denormalize_regions ();
void audition_region_from_region_list ();
void hide_region_from_region_list ();
@ -1670,8 +1661,8 @@ class Editor : public PublicEditor
static void* _freeze_thread (void*);
void* freeze_thread ();
void freeze_route ();
void unfreeze_route ();
void freeze_routes ();
void unfreeze_routes ();
/* edit-group solo + mute */
@ -1734,7 +1725,7 @@ class Editor : public PublicEditor
/* nudging tracks */
void nudge_track (bool use_edit_cursor, bool forwards);
void nudge_selected_tracks (bool use_edit_cursor, bool forwards);
/* xfades */
@ -1827,8 +1818,8 @@ class Editor : public PublicEditor
bool _new_regionviews_show_envelope;
void toggle_gain_envelope_visibility ();
void toggle_gain_envelope_active ();
void set_gain_envelope_visibility (bool);
void set_gain_envelope_active (bool);
void reset_region_gain_envelopes ();
Gtk::CheckMenuItem* region_envelope_visible_item;

View File

@ -248,9 +248,9 @@ Editor::register_actions ()
ActionManager::session_sensitive_actions.push_back (act);
act = ActionManager::register_action (editor_actions, "insert-region", _("Insert Region"), mem_fun(*this, &Editor::keyboard_insert_region_list_selection));
ActionManager::session_sensitive_actions.push_back (act);
act = ActionManager::register_action (editor_actions, "reverse-region", _("Reverse Region"), mem_fun(*this, &Editor::reverse_region));
act = ActionManager::register_action (editor_actions, "reverse-region", _("Reverse Regions"), mem_fun(*this, &Editor::reverse_regions));
ActionManager::session_sensitive_actions.push_back (act);
act = ActionManager::register_action (editor_actions, "normalize-region", _("Normalize Region"), mem_fun(*this, &Editor::normalize_region));
act = ActionManager::register_action (editor_actions, "normalize-region", _("Normalize Regions"), mem_fun(*this, &Editor::normalize_regions));
ActionManager::session_sensitive_actions.push_back (act);
act = ActionManager::register_action (editor_actions, "crop", _("crop"), mem_fun(*this, &Editor::crop_region_to_selection));
ActionManager::session_sensitive_actions.push_back (act);

View File

@ -87,19 +87,20 @@ Editor::export_range (nframes_t start, nframes_t end)
}
}
/** Export the first selected region */
void
Editor::export_region ()
{
if (clicked_regionview == 0) {
if (selection->regions.empty()) {
return;
}
ExportDialog* dialog = new ExportRegionDialog (*this, clicked_regionview->region());
boost::shared_ptr<Region> r = selection->regions.front()->region();
ExportDialog* dialog = new ExportRegionDialog (*this, r);
dialog->connect_to_session (session);
dialog->set_range (
clicked_regionview->region()->first_frame(),
clicked_regionview->region()->last_frame());
dialog->set_range (r->first_frame(), r->last_frame());
dialog->start_export();
}

View File

@ -330,22 +330,8 @@ Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType it
switch (item_type) {
case RegionItem:
if (mouse_mode != MouseRange) {
commit = set_selected_regionview_from_click (press, op, true);
} else if (event->type == GDK_BUTTON_PRESS) {
commit = set_selected_track_from_click (press, op, false);
}
break;
case RegionViewNameHighlight:
case RegionViewName:
if (mouse_mode != MouseRange) {
commit = set_selected_regionview_from_click (press, op, true);
} else if (event->type == GDK_BUTTON_PRESS) {
commit = set_selected_track_from_click (press, op, false);
}
break;
case FadeInHandleItem:
case FadeInItem:
case FadeOutHandleItem:
@ -356,7 +342,11 @@ Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType it
commit = set_selected_track_from_click (press, op, false);
}
break;
case CrossfadeViewItem:
commit = set_selected_track_from_click (press, op, false);
break;
case GainAutomationControlPointItem:
case PanAutomationControlPointItem:
case RedirectAutomationControlPointItem:
@ -825,21 +815,13 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
break;
case StreamItem:
popup_track_context_menu (1, event->button.time, item_type, false, where);
break;
case RegionItem:
case RegionViewNameHighlight:
case RegionViewName:
popup_track_context_menu (1, event->button.time, item_type, false, where);
break;
case SelectionItem:
popup_track_context_menu (1, event->button.time, item_type, true, where);
break;
case AutomationTrackItem:
popup_track_context_menu (1, event->button.time, item_type, false, where);
case CrossfadeViewItem:
popup_track_context_menu (1, event->button.time, where);
break;
case MarkerBarItem:
@ -862,10 +844,6 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
tm_marker_context_menu (&event->button, item);
break;
case CrossfadeViewItem:
popup_track_context_menu (1, event->button.time, item_type, false, where);
break;
/* <CMT Additions> */
case ImageFrameItem:
popup_imageframe_edit_menu(1, event->button.time, item, true) ;

View File

@ -143,6 +143,8 @@ Editor::split_regions_at (nframes_t where, RegionSelection& regions)
_new_regionviews_show_envelope = false;
}
/** Remove `clicked_regionview' */
void
Editor::remove_clicked_region ()
{
@ -160,47 +162,29 @@ Editor::remove_clicked_region ()
commit_reversible_command ();
}
/** Remove the selected regions */
void
Editor::destroy_clicked_region ()
Editor::remove_selected_regions ()
{
uint32_t selected = selection->regions.size();
if (!session || !selected) {
if (selection->regions.empty()) {
return;
}
vector<string> choices;
string prompt;
/* XXX: should be called remove regions if we're removing more than one */
begin_reversible_command (_("remove region"));
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);
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
boost::shared_ptr<Region> region = (*i)->region ();
boost::shared_ptr<Playlist> playlist = region->playlist ();
if (prompter.run() == 0) { /* first choice */
return;
XMLNode &before = playlist->get_state();
playlist->remove_region (region);
XMLNode &after = playlist->get_state();
session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
}
if (selected) {
list<boost::shared_ptr<Region> > r;
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
r.push_back ((*i)->region());
}
session->destroy_regions (r);
}
commit_reversible_command ();
}
boost::shared_ptr<Region>
@ -1534,13 +1518,11 @@ Editor::insert_region_list_selection (float times)
RouteTimeAxisView *tv = 0;
boost::shared_ptr<Playlist> playlist;
if (clicked_routeview != 0) {
tv = clicked_routeview;
} else if (!selection->tracks.empty()) {
if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
return;
}
} else {
if (selection->tracks.empty()) {
return;
}
if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
return;
}
@ -1748,14 +1730,11 @@ Editor::lower_region_to_bottom ()
selection->foreach_region (&Region::lower_to_bottom);
}
/** Show the region editor for the selected regions */
void
Editor::edit_region ()
{
if (clicked_regionview == 0) {
return;
}
clicked_regionview->show_region_editor ();
selection->foreach_regionview (&RegionView::show_region_editor);
}
void
@ -1832,6 +1811,7 @@ Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Ro
/* XXX how to unset the solo state ? */
}
/** Start an audition of the first selected region */
void
Editor::audition_selected_region ()
{
@ -2270,39 +2250,50 @@ Editor::set_a_regions_sync_position (boost::shared_ptr<Region> region, nframes_t
commit_reversible_command ();
}
/** Set the sync position of the selection using the position of the edit cursor */
void
Editor::set_region_sync_from_edit_cursor ()
{
if (clicked_regionview == 0) {
return;
/* Check that at the edit cursor is in at least one of the selected regions */
RegionSelection::const_iterator i = selection->regions.begin();
while (i != selection->regions.end() && !(*i)->region()->covers (edit_cursor->current_frame)) {
++i;
}
if (!clicked_regionview->region()->covers (edit_cursor->current_frame)) {
/* Give the user a hint if not */
if (i == selection->regions.end()) {
error << _("Place the edit cursor at the desired sync point") << endmsg;
return;
}
boost::shared_ptr<Region> region (clicked_regionview->region());
begin_reversible_command (_("set sync from edit cursor"));
XMLNode &before = region->playlist()->get_state();
region->set_sync_position (edit_cursor->current_frame);
XMLNode &after = region->playlist()->get_state();
session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
for (RegionSelection::iterator j = selection->regions.begin(); j != selection->regions.end(); ++j) {
boost::shared_ptr<Region> r = (*j)->region();
XMLNode &before = r->playlist()->get_state();
r->set_sync_position (edit_cursor->current_frame);
XMLNode &after = r->playlist()->get_state();
session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
}
commit_reversible_command ();
}
/** Remove the sync positions of the selection */
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 ();
begin_reversible_command (_("remove sync"));
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
boost::shared_ptr<Region> r = (*i)->region();
XMLNode &before = r->playlist()->get_state();
r->clear_sync_position ();
XMLNode &after = r->playlist()->get_state();
session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
}
commit_reversible_command ();
}
void
@ -2447,66 +2438,80 @@ Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint poi
session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
}
/** Trim the end of the selected regions to the position of the edit cursor */
void
Editor::trim_region_to_edit_cursor ()
{
if (clicked_regionview == 0) {
if (selection->regions.empty()) {
return;
}
boost::shared_ptr<Region> region (clicked_regionview->region());
float speed = 1.0f;
RouteTimeAxisView *rtav;
if ( clicked_axisview != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(clicked_axisview)) != 0 ) {
if (rtav->get_diskstream() != 0) {
speed = rtav->get_diskstream()->speed();
}
}
begin_reversible_command (_("trim to edit"));
XMLNode &before = region->playlist()->get_state();
region->trim_end( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
XMLNode &after = region->playlist()->get_state();
session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
boost::shared_ptr<Region> region ((*i)->region());
float speed = 1.0f;
RouteTimeAxisView *rtav;
/* XXX I don't think clicked_axisview should be used here! */
if ( clicked_axisview != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(clicked_axisview)) != 0 ) {
if (rtav->get_diskstream() != 0) {
speed = rtav->get_diskstream()->speed();
}
}
XMLNode &before = region->playlist()->get_state();
region->trim_end( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
XMLNode &after = region->playlist()->get_state();
session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
}
commit_reversible_command ();
}
/** Trim the start of the selected regions to the position of the edit cursor */
void
Editor::trim_region_from_edit_cursor ()
{
if (clicked_regionview == 0) {
if (selection->regions.empty()) {
return;
}
boost::shared_ptr<Region> region (clicked_regionview->region());
float speed = 1.0f;
RouteTimeAxisView *rtav;
if ( clicked_axisview != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(clicked_axisview)) != 0 ) {
if (rtav->get_diskstream() != 0) {
speed = rtav->get_diskstream()->speed();
}
}
begin_reversible_command (_("trim to edit"));
XMLNode &before = region->playlist()->get_state();
region->trim_front ( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
XMLNode &after = region->playlist()->get_state();
session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
boost::shared_ptr<Region> region ((*i)->region());
float speed = 1.0f;
RouteTimeAxisView *rtav;
/* XXX: not sure about clicked_axisview here */
if ( clicked_axisview != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(clicked_axisview)) != 0 ) {
if (rtav->get_diskstream() != 0) {
speed = rtav->get_diskstream()->speed();
}
}
XMLNode &before = region->playlist()->get_state();
region->trim_front ( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
XMLNode &after = region->playlist()->get_state();
session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
}
commit_reversible_command ();
}
/** Unfreeze selected routes */
void
Editor::unfreeze_route ()
Editor::unfreeze_routes ()
{
if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
return;
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*i);
if (atv && atv->is_audio_track()) {
atv->audio_track()->unfreeze ();
}
}
clicked_routeview->track()->unfreeze ();
}
void*
@ -2519,7 +2524,15 @@ Editor::_freeze_thread (void* arg)
void*
Editor::freeze_thread ()
{
clicked_routeview->audio_track()->freeze (*current_interthread_info);
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*i);
if (atv && atv->is_audio_track()) {
atv->audio_track()->freeze (*current_interthread_info);
}
}
current_interthread_info->done = true;
return 0;
}
@ -2530,13 +2543,10 @@ Editor::freeze_progress_timeout (void *arg)
return !(current_interthread_info->done || current_interthread_info->cancel);
}
/** Freeze selected routes */
void
Editor::freeze_route ()
Editor::freeze_routes ()
{
if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
return;
}
InterThreadInfo itt;
if (interthread_progress_window == 0) {
@ -2624,18 +2634,50 @@ Editor::bounce_range_selection ()
commit_reversible_command ();
}
/** Cut selected regions, automation points or a time range */
void
Editor::cut ()
{
cut_copy (Cut);
}
/** Copy selected regions, automation points or a time range */
void
Editor::copy ()
{
cut_copy (Copy);
}
/** @return true if a Cut, Copy or Clear is possible */
bool
Editor::can_cut_copy () const
{
switch (current_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;
}
return false;
}
/** Cut, copy or clear selected regions, automation points or a time range.
* @param op Operation (Cut, Copy or Clear)
*/
void
Editor::cut_copy (CutCopyOp op)
{
@ -2703,6 +2745,9 @@ Editor::cut_copy (CutCopyOp op)
}
}
/** Cut, copy or clear selected automation points.
* @param op Operation (Cut, Copy or Clear)
*/
void
Editor::cut_copy_points (CutCopyOp op)
{
@ -2734,6 +2779,10 @@ struct PlaylistMapping {
PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
};
/** Cut, copy or clear selected regions.
* @param op Operation (Cut, Copy or Clear)
*/
void
Editor::cut_copy_regions (CutCopyOp op)
{
@ -3109,7 +3158,7 @@ Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
}
void
Editor::nudge_track (bool use_edit_cursor, bool forwards)
Editor::nudge_selected_tracks (bool use_edit_cursor, bool forwards)
{
boost::shared_ptr<Playlist> playlist;
nframes_t distance;
@ -3176,7 +3225,7 @@ Editor::remove_last_capture ()
}
void
Editor::normalize_region ()
Editor::normalize_regions ()
{
if (!session) {
return;
@ -3206,7 +3255,7 @@ Editor::normalize_region ()
void
Editor::denormalize_region ()
Editor::denormalize_regions ()
{
if (!session) {
return;
@ -3232,7 +3281,7 @@ Editor::denormalize_region ()
void
Editor::reverse_region ()
Editor::reverse_regions ()
{
if (!session) {
return;
@ -3317,10 +3366,6 @@ Editor::region_selection_op (void (Region::*pmf)(bool), bool yn)
void
Editor::external_edit_region ()
{
if (!clicked_regionview) {
return;
}
/* more to come */
}
@ -3368,71 +3413,75 @@ Editor::reset_region_gain_envelopes ()
session->commit_reversible_command ();
}
/** Set whether or not gain envelopes are visible for the selected regions.
* @param yn true to make visible, false to make invisible.
*/
void
Editor::toggle_gain_envelope_visibility ()
Editor::set_gain_envelope_visibility (bool yn)
{
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
if (arv) {
bool x = region_envelope_visible_item->get_active();
if (x != arv->envelope_visible()) {
arv->set_envelope_visible (x);
if (arv->envelope_visible() != yn) {
arv->set_envelope_visible (yn);
}
}
}
}
/** Set whether or not gain envelopes are active for the selected regions.
* @param yn true to make active, false to make inactive.
*/
void
Editor::set_gain_envelope_active (bool yn)
{
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
if (arv) {
if (arv->audio_region()->envelope_active() != yn) {
arv->audio_region()->set_envelope_active (yn);
}
}
}
}
/** Set the locked state of all selected regions to a particular value.
* @param yn true to make locked, false to make unlocked.
*/
void
Editor::set_region_lock (bool yn)
{
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
if (arv) {
if (arv->audio_region()->locked() != yn) {
arv->audio_region()->set_locked (yn);
}
}
}
}
void
Editor::toggle_gain_envelope_active ()
Editor::set_region_mute (bool yn)
{
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
if (arv) {
bool x = region_envelope_active_item->get_active();
if (x != arv->audio_region()->envelope_active()) {
arv->audio_region()->set_envelope_active (x);
if (arv->audio_region()->muted() != yn) {
arv->audio_region()->set_muted (yn);
}
}
}
}
void
Editor::toggle_region_lock ()
Editor::set_region_opaque (bool yn)
{
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
if (arv) {
bool x = region_lock_item->get_active();
if (x != arv->audio_region()->locked()) {
arv->audio_region()->set_locked (x);
}
}
}
}
void
Editor::toggle_region_mute ()
{
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
if (arv) {
bool x = region_mute_item->get_active();
if (x != arv->audio_region()->muted()) {
arv->audio_region()->set_muted (x);
}
}
}
}
void
Editor::toggle_region_opaque ()
{
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
if (arv) {
bool x = region_opaque_item->get_active();
if (x != arv->audio_region()->opaque()) {
arv->audio_region()->set_opaque (x);
if (arv->audio_region()->opaque() != yn) {
arv->audio_region()->set_opaque (yn);
}
}
}

View File

@ -582,43 +582,6 @@ Editor::set_selected_regionview_from_region_list (boost::shared_ptr<Region> regi
commit_reversible_command () ;
}
bool
Editor::set_selected_regionview_from_map_event (GdkEventAny* ev, StreamView* sv, boost::weak_ptr<Region> weak_r)
{
RegionView* rv;
boost::shared_ptr<Region> r (weak_r.lock());
if (!r) {
return true;
}
boost::shared_ptr<AudioRegion> ar;
if ((ar = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
return true;
}
if ((rv = sv->find_view (ar)) == 0) {
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);
commit_reversible_command () ;
return true;
}
void
Editor::track_selection_changed ()
{
@ -685,16 +648,17 @@ Editor::point_selection_changed ()
}
}
/** Select everything in the selected tracks
* @param Selection operation to apply.
*/
void
Editor::select_all_in_track (Selection::Operation op)
Editor::select_all_in_selected_tracks (Selection::Operation op)
{
list<Selectable *> touched;
if (!clicked_routeview) {
return;
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
(*i)->get_selectables (0, max_frames, 0, DBL_MAX, touched);
}
clicked_routeview->get_selectables (0, max_frames, 0, DBL_MAX, touched);
switch (op) {
case Selection::Toggle:
@ -741,16 +705,16 @@ Editor::select_all (Selection::Operation op)
commit_reversible_command ();
}
/** Invert the selection in the selected tracks */
void
Editor::invert_selection_in_track ()
Editor::invert_selection_in_selected_tracks ()
{
list<Selectable *> touched;
if (!clicked_routeview) {
return;
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
(*i)->get_inverted_selectables (*selection, touched);
}
clicked_routeview->get_inverted_selectables (*selection, touched);
selection->set (touched);
}

View File

@ -91,7 +91,7 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulThingWithGoingAway
virtual void redo (uint32_t n = 1) = 0;
virtual void set_mouse_mode (Editing::MouseMode, bool force = false) = 0;
virtual void step_mouse_mode (bool next) = 0;
virtual Editing::MouseMode current_mouse_mode () = 0;
virtual Editing::MouseMode current_mouse_mode () const = 0;
virtual void add_imageframe_time_axis(const std::string & track_name, void*) = 0;
virtual void add_imageframe_marker_time_axis(const std::string & track_name, TimeAxisView* marked_track, void*) = 0;
virtual void connect_to_image_compositor() = 0;

View File

@ -1048,6 +1048,9 @@ RouteTimeAxisView::set_selected_regionviews (RegionSelection& regions)
}
}
/** Add the selectable things that we have to a list.
* @param results List to add things to.
*/
void
RouteTimeAxisView::get_selectables (nframes_t start, nframes_t end, double top, double bot, list<Selectable*>& results)
{

View File

@ -45,6 +45,10 @@ namespace ARDOUR {
class AutomationList;
}
/// Lists of selected things
/** The Selection class holds lists of selected items (tracks, regions, etc. etc.). */
class Selection : public sigc::trackable
{
public:
@ -149,6 +153,7 @@ class Selection : public sigc::trackable
void clear_points ();
void foreach_region (void (ARDOUR::Region::*method)(void));
void foreach_regionview (void (RegionView::*method)(void));
template<class A> void foreach_region (void (ARDOUR::Region::*method)(A), A arg);
private:

View File

@ -38,6 +38,13 @@ Selection::foreach_region (void (ARDOUR::Region::*method)(void)) {
}
}
inline void
Selection::foreach_regionview (void (RegionView::*method)(void)) {
for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
((*i)->*(method))();
}
}
template<class A> inline void
Selection::foreach_region (void (ARDOUR::Region::*method)(A), A arg) {
for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {

View File

@ -741,6 +741,7 @@ AudioTrack::bounce (InterThreadInfo& itt)
{
vector<boost::shared_ptr<Source> > srcs;
_session.write_one_audio_track (*this, 0, _session.current_end_frame(), false, srcs, itt);
itt.done = true;
}
@ -749,6 +750,7 @@ AudioTrack::bounce_range (nframes_t start, nframes_t end, InterThreadInfo& itt)
{
vector<boost::shared_ptr<Source> > srcs;
_session.write_one_audio_track (*this, start, end, false, srcs, itt);
itt.done = true;
}
void

View File

@ -4164,8 +4164,6 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le
g_atomic_int_set (&processing_prohibited, 0);
itt.done = true;
return ret;
}