2007-01-28 12:44:13 -05:00
|
|
|
/*
|
2019-08-02 17:26:43 -04:00
|
|
|
* Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
|
|
|
|
* Copyright (C) 2007-2015 David Robillard <d@drobilla.net>
|
|
|
|
* Copyright (C) 2007-2018 Paul Davis <paul@linuxaudiosystems.com>
|
|
|
|
* Copyright (C) 2013-2017 Nick Mainsbridge <mainsbridge@gmail.com>
|
|
|
|
* Copyright (C) 2013-2019 Robin Gareus <robin@gareus.org>
|
|
|
|
* Copyright (C) 2014-2019 Ben Loftis <ben@harrisonconsoles.com>
|
|
|
|
* Copyright (C) 2015 André Nusser <andre.nusser@googlemail.com>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
*/
|
2007-01-28 12:44:13 -05:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
#include <algorithm>
|
2008-09-10 11:03:30 -04:00
|
|
|
#include <cstdlib>
|
2008-01-10 16:20:59 -05:00
|
|
|
|
2017-02-17 19:25:13 -05:00
|
|
|
#include "pbd/unwind.h"
|
2007-01-28 12:44:13 -05:00
|
|
|
|
2017-05-12 09:51:31 -04:00
|
|
|
#include "ardour/control_protocol_manager.h"
|
2012-05-24 02:09:29 -04:00
|
|
|
#include "ardour/midi_region.h"
|
2009-02-25 13:26:51 -05:00
|
|
|
#include "ardour/playlist.h"
|
|
|
|
#include "ardour/profile.h"
|
2012-05-24 02:09:29 -04:00
|
|
|
#include "ardour/route_group.h"
|
2017-05-05 07:31:49 -04:00
|
|
|
#include "ardour/selection.h"
|
2012-05-24 02:09:29 -04:00
|
|
|
#include "ardour/session.h"
|
2017-08-07 11:34:03 -04:00
|
|
|
#include "ardour/vca.h"
|
2007-01-28 12:44:13 -05:00
|
|
|
|
|
|
|
#include "editor.h"
|
2017-05-05 07:31:49 -04:00
|
|
|
#include "editor_drag.h"
|
|
|
|
#include "editor_routes.h"
|
2023-09-07 15:20:05 -04:00
|
|
|
#include "editor_section_box.h"
|
2019-07-30 14:02:15 -04:00
|
|
|
#include "editor_sources.h"
|
2007-01-28 12:44:13 -05:00
|
|
|
#include "actions.h"
|
|
|
|
#include "audio_time_axis.h"
|
|
|
|
#include "audio_region_view.h"
|
|
|
|
#include "audio_streamview.h"
|
|
|
|
#include "automation_line.h"
|
2007-07-06 23:19:04 -04:00
|
|
|
#include "control_point.h"
|
2009-07-03 18:42:22 -04:00
|
|
|
#include "editor_regions.h"
|
2010-11-16 09:53:16 -05:00
|
|
|
#include "editor_cursors.h"
|
2020-04-16 14:16:45 -04:00
|
|
|
#include "keyboard.h"
|
2011-01-26 20:31:03 -05:00
|
|
|
#include "midi_region_view.h"
|
2015-09-20 14:03:09 -04:00
|
|
|
#include "sfdb_ui.h"
|
2007-01-28 12:44:13 -05:00
|
|
|
|
2016-07-14 14:44:52 -04:00
|
|
|
#include "pbd/i18n.h"
|
2007-01-28 12:44:13 -05:00
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
using namespace ARDOUR;
|
|
|
|
using namespace PBD;
|
|
|
|
using namespace Gtk;
|
|
|
|
using namespace Glib;
|
|
|
|
using namespace Gtkmm2ext;
|
|
|
|
using namespace Editing;
|
|
|
|
|
|
|
|
struct TrackViewByPositionSorter
|
|
|
|
{
|
2011-10-07 16:09:01 -04:00
|
|
|
bool operator() (const TimeAxisView* a, const TimeAxisView *b) {
|
|
|
|
return a->y_position() < b->y_position();
|
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
bool
|
2009-07-09 13:58:13 -04:00
|
|
|
Editor::extend_selection_to_track (TimeAxisView& view)
|
2007-01-28 12:44:13 -05:00
|
|
|
{
|
2009-07-09 13:58:13 -04:00
|
|
|
if (selection->selected (&view)) {
|
2007-01-28 12:44:13 -05:00
|
|
|
/* already selected, do nothing */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (selection->tracks.empty()) {
|
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
if (!selection->selected (&view)) {
|
|
|
|
selection->set (&view);
|
2007-01-28 12:44:13 -05:00
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
|
|
|
|
/* something is already selected, so figure out which range of things to add */
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
TrackViewList to_be_added;
|
|
|
|
TrackViewList sorted = track_views;
|
|
|
|
TrackViewByPositionSorter cmp;
|
|
|
|
bool passed_clicked = false;
|
|
|
|
bool forwards = true;
|
|
|
|
|
|
|
|
sorted.sort (cmp);
|
|
|
|
|
|
|
|
/* figure out if we should go forward or backwards */
|
|
|
|
|
|
|
|
for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
|
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
if ((*i) == &view) {
|
2007-01-28 12:44:13 -05:00
|
|
|
passed_clicked = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (selection->selected (*i)) {
|
|
|
|
if (passed_clicked) {
|
|
|
|
forwards = true;
|
|
|
|
} else {
|
|
|
|
forwards = false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
passed_clicked = false;
|
|
|
|
|
|
|
|
if (forwards) {
|
|
|
|
|
|
|
|
for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
if ((*i) == &view) {
|
2007-01-28 12:44:13 -05:00
|
|
|
passed_clicked = true;
|
|
|
|
continue;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
if (passed_clicked) {
|
|
|
|
if ((*i)->hidden()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (selection->selected (*i)) {
|
|
|
|
break;
|
|
|
|
} else if (!(*i)->hidden()) {
|
|
|
|
to_be_added.push_back (*i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
for (TrackViewList::reverse_iterator r = sorted.rbegin(); r != sorted.rend(); ++r) {
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
if ((*r) == &view) {
|
2007-01-28 12:44:13 -05:00
|
|
|
passed_clicked = true;
|
|
|
|
continue;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
if (passed_clicked) {
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
if ((*r)->hidden()) {
|
|
|
|
continue;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
if (selection->selected (*r)) {
|
|
|
|
break;
|
|
|
|
} else if (!(*r)->hidden()) {
|
|
|
|
to_be_added.push_back (*r);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2017-02-26 12:22:39 -05:00
|
|
|
if (!selection->selected (&view)) {
|
|
|
|
to_be_added.push_back (&view);
|
|
|
|
}
|
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
if (!to_be_added.empty()) {
|
|
|
|
selection->add (to_be_added);
|
|
|
|
return true;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-03-18 02:07:08 -04:00
|
|
|
void
|
|
|
|
Editor::select_all_tracks ()
|
2020-01-22 11:30:05 -05:00
|
|
|
{
|
|
|
|
TrackViewList tracks;
|
|
|
|
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
|
|
|
|
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i);
|
|
|
|
if ( rtv && rtv->route()->is_track() ) {
|
|
|
|
tracks.push_back (*i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
PBD::Unwinder<bool> uw (_track_selection_change_without_scroll, true);
|
|
|
|
selection->set (tracks);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::select_all_visible_lanes ()
|
2007-03-18 02:07:08 -04:00
|
|
|
{
|
2008-10-14 10:20:29 -04:00
|
|
|
TrackViewList visible_views;
|
|
|
|
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
|
|
|
|
if ((*i)->marked_for_display()) {
|
|
|
|
visible_views.push_back (*i);
|
|
|
|
}
|
|
|
|
}
|
2017-02-17 19:25:13 -05:00
|
|
|
PBD::Unwinder<bool> uw (_track_selection_change_without_scroll, true);
|
2008-10-14 10:20:29 -04:00
|
|
|
selection->set (visible_views);
|
2007-03-18 02:07:08 -04:00
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
|
2010-08-06 19:28:44 -04:00
|
|
|
/** Select clicked_axisview, unless there are no currently selected
|
2010-01-01 17:11:15 -05:00
|
|
|
* tracks, in which case nothing will happen unless `force' is true.
|
|
|
|
*/
|
2008-01-10 16:20:59 -05:00
|
|
|
void
|
2022-07-14 18:28:07 -04:00
|
|
|
Editor::set_selected_track_as_side_effect (Selection::Operation op, Controllable::GroupControlDisposition gcd)
|
2008-01-10 16:20:59 -05:00
|
|
|
{
|
2010-08-06 19:28:44 -04:00
|
|
|
if (!clicked_axisview) {
|
2008-01-10 16:20:59 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-10-21 11:27:03 -04:00
|
|
|
PBD::Unwinder<bool> uw (_editor_track_selection_change_without_scroll, true);
|
2017-10-20 13:08:48 -04:00
|
|
|
|
2014-08-05 16:42:06 -04:00
|
|
|
RouteGroup* group = NULL;
|
|
|
|
if (clicked_routeview) {
|
|
|
|
group = clicked_routeview->route()->route_group();
|
2011-10-07 16:09:01 -04:00
|
|
|
}
|
2010-08-26 19:25:44 -04:00
|
|
|
|
|
|
|
switch (op) {
|
2011-06-01 13:00:29 -04:00
|
|
|
case Selection::Toggle:
|
2010-08-26 19:25:44 -04:00
|
|
|
if (selection->selected (clicked_axisview)) {
|
2021-05-28 13:40:11 -04:00
|
|
|
if (group && group->is_active() && group->enabled_property(ARDOUR::Properties::group_select.property_id)) {
|
2010-08-26 19:25:44 -04:00
|
|
|
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
|
2022-07-14 18:28:07 -04:00
|
|
|
if ((*i)->route_group() == group && gcd != Controllable::NoGroup) {
|
2010-08-26 19:25:44 -04:00
|
|
|
selection->remove(*i);
|
2015-01-10 12:07:31 -05:00
|
|
|
}
|
2010-08-26 19:25:44 -04:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
selection->remove (clicked_axisview);
|
2011-10-07 16:09:01 -04:00
|
|
|
}
|
2010-08-26 19:25:44 -04:00
|
|
|
} else {
|
2021-05-28 13:40:11 -04:00
|
|
|
if (group && group->is_active() && group->enabled_property(ARDOUR::Properties::group_select.property_id)) {
|
2010-08-26 19:25:44 -04:00
|
|
|
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
|
2022-07-14 18:28:07 -04:00
|
|
|
if ((*i)->route_group() == group && gcd != Controllable::NoGroup) {
|
2010-08-26 19:25:44 -04:00
|
|
|
selection->add(*i);
|
2015-01-10 12:07:31 -05:00
|
|
|
}
|
2010-08-26 19:25:44 -04:00
|
|
|
}
|
2011-10-07 16:09:01 -04:00
|
|
|
} else {
|
|
|
|
selection->add (clicked_axisview);
|
|
|
|
}
|
2010-08-26 19:25:44 -04:00
|
|
|
}
|
2011-10-07 16:09:01 -04:00
|
|
|
break;
|
2011-06-01 13:00:29 -04:00
|
|
|
|
|
|
|
case Selection::Add:
|
2021-05-28 13:40:11 -04:00
|
|
|
if (group && group->is_active() && group->enabled_property(ARDOUR::Properties::group_select.property_id)) {
|
2010-08-30 13:34:12 -04:00
|
|
|
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
|
2022-07-14 18:28:07 -04:00
|
|
|
if ((*i)->route_group() == group && gcd != Controllable::NoGroup) {
|
2010-08-30 13:34:12 -04:00
|
|
|
selection->add(*i);
|
2015-01-10 12:07:31 -05:00
|
|
|
}
|
2010-08-30 13:34:12 -04:00
|
|
|
}
|
2011-10-07 16:09:01 -04:00
|
|
|
} else {
|
2010-08-30 13:34:12 -04:00
|
|
|
selection->add (clicked_axisview);
|
2011-10-07 16:09:01 -04:00
|
|
|
}
|
|
|
|
break;
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-08-26 19:25:44 -04:00
|
|
|
case Selection::Set:
|
2011-10-07 16:09:01 -04:00
|
|
|
selection->clear();
|
2021-05-28 13:40:11 -04:00
|
|
|
if (group && group->is_active() && group->enabled_property(ARDOUR::Properties::group_select.property_id)) {
|
2010-08-26 19:25:44 -04:00
|
|
|
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
|
2022-07-14 18:28:07 -04:00
|
|
|
if ((*i)->route_group() == group && gcd != Controllable::NoGroup) {
|
2010-08-26 19:25:44 -04:00
|
|
|
selection->add(*i);
|
2015-01-10 12:07:31 -05:00
|
|
|
}
|
2010-08-26 19:25:44 -04:00
|
|
|
}
|
2011-10-07 16:09:01 -04:00
|
|
|
} else {
|
2010-08-26 19:25:44 -04:00
|
|
|
selection->set (clicked_axisview);
|
2011-10-07 16:09:01 -04:00
|
|
|
}
|
|
|
|
break;
|
2011-06-01 13:00:29 -04:00
|
|
|
|
|
|
|
case Selection::Extend:
|
2010-08-26 19:25:44 -04:00
|
|
|
selection->clear();
|
2011-10-07 16:09:01 -04:00
|
|
|
break;
|
2010-08-26 19:25:44 -04:00
|
|
|
}
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-07-09 13:58:13 -04:00
|
|
|
Editor::set_selected_track (TimeAxisView& view, Selection::Operation op, bool no_remove)
|
2007-01-28 12:44:13 -05:00
|
|
|
{
|
2015-03-25 08:31:23 -04:00
|
|
|
begin_reversible_selection_op (X_("Set Selected Track"));
|
2014-12-22 08:30:23 -05:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
switch (op) {
|
|
|
|
case Selection::Toggle:
|
2009-07-09 13:58:13 -04:00
|
|
|
if (selection->selected (&view)) {
|
2007-01-28 12:44:13 -05:00
|
|
|
if (!no_remove) {
|
2009-07-09 13:58:13 -04:00
|
|
|
selection->remove (&view);
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
} else {
|
2009-07-09 13:58:13 -04:00
|
|
|
selection->add (&view);
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Selection::Add:
|
2017-05-05 07:31:49 -04:00
|
|
|
selection->add (&view);
|
2007-01-28 12:44:13 -05:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Selection::Set:
|
2009-07-09 13:58:13 -04:00
|
|
|
selection->set (&view);
|
2007-01-28 12:44:13 -05:00
|
|
|
break;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
case Selection::Extend:
|
2008-01-10 16:20:59 -05:00
|
|
|
extend_selection_to_track (view);
|
2007-01-28 12:44:13 -05:00
|
|
|
break;
|
|
|
|
}
|
2014-12-22 08:30:23 -05:00
|
|
|
|
|
|
|
commit_reversible_selection_op ();
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
void
|
2007-01-28 12:44:13 -05:00
|
|
|
Editor::set_selected_track_from_click (bool press, Selection::Operation op, bool no_remove)
|
|
|
|
{
|
|
|
|
if (!clicked_routeview) {
|
2008-01-10 16:20:59 -05:00
|
|
|
return;
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
if (!press) {
|
2008-01-10 16:20:59 -05:00
|
|
|
return;
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
set_selected_track (*clicked_routeview, op, no_remove);
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2012-04-22 19:14:27 -04:00
|
|
|
Editor::set_selected_control_point_from_click (bool press, Selection::Operation op)
|
2007-01-28 12:44:13 -05:00
|
|
|
{
|
|
|
|
if (!clicked_control_point) {
|
|
|
|
return false;
|
|
|
|
}
|
2015-09-13 15:24:28 -04:00
|
|
|
|
2023-08-18 19:39:44 -04:00
|
|
|
if (mouse_mode != Editing::MouseContent) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-06-17 13:48:39 -04:00
|
|
|
bool ret = false;
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-08-10 21:23:03 -04:00
|
|
|
switch (op) {
|
|
|
|
case Selection::Set:
|
2015-09-13 15:24:28 -04:00
|
|
|
if (!selection->selected (clicked_control_point)) {
|
2012-05-31 10:39:48 -04:00
|
|
|
selection->set (clicked_control_point);
|
2015-06-17 13:48:39 -04:00
|
|
|
ret = true;
|
2015-09-13 15:24:28 -04:00
|
|
|
} else {
|
|
|
|
/* clicked on an already selected point */
|
|
|
|
if (press) {
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
if (selection->points.size() > 1) {
|
|
|
|
selection->set (clicked_control_point);
|
|
|
|
ret = true;
|
|
|
|
}
|
|
|
|
}
|
2012-05-31 10:39:48 -04:00
|
|
|
}
|
2010-08-10 21:23:03 -04:00
|
|
|
break;
|
2015-09-13 15:24:28 -04:00
|
|
|
|
2010-08-10 21:23:03 -04:00
|
|
|
case Selection::Add:
|
2012-05-31 10:39:48 -04:00
|
|
|
if (press) {
|
|
|
|
selection->add (clicked_control_point);
|
2015-06-17 13:48:39 -04:00
|
|
|
ret = true;
|
2012-05-31 10:39:48 -04:00
|
|
|
}
|
2010-08-10 21:23:03 -04:00
|
|
|
break;
|
|
|
|
case Selection::Toggle:
|
2015-06-17 13:48:39 -04:00
|
|
|
|
2012-05-31 10:39:48 -04:00
|
|
|
/* This is a bit of a hack; if we Primary-Click-Drag a control
|
|
|
|
point (for push drag) we want the point we clicked on to be
|
|
|
|
selected, otherwise we end up confusingly dragging an
|
|
|
|
unselected point. So here we ensure that the point is selected
|
|
|
|
after the press, and if we subsequently get a release (meaning no
|
|
|
|
drag occurred) we set things up so that the toggle has happened.
|
|
|
|
*/
|
|
|
|
if (press && !selection->selected (clicked_control_point)) {
|
|
|
|
/* This is the button press, and the control point is not selected; make it so,
|
|
|
|
in case this press leads to a drag. Also note that having done this, we don't
|
|
|
|
need to toggle again on release.
|
|
|
|
*/
|
|
|
|
selection->toggle (clicked_control_point);
|
|
|
|
_control_point_toggled_on_press = true;
|
2015-06-17 13:48:39 -04:00
|
|
|
ret = true;
|
2012-05-31 10:39:48 -04:00
|
|
|
} else if (!press && !_control_point_toggled_on_press) {
|
|
|
|
/* This is the release, and the point wasn't toggled on the press, so do it now */
|
|
|
|
selection->toggle (clicked_control_point);
|
2015-06-17 13:48:39 -04:00
|
|
|
ret = true;
|
2012-05-31 10:39:48 -04:00
|
|
|
} else {
|
|
|
|
/* Reset our flag */
|
|
|
|
_control_point_toggled_on_press = false;
|
|
|
|
}
|
2010-08-10 21:23:03 -04:00
|
|
|
break;
|
|
|
|
case Selection::Extend:
|
|
|
|
/* XXX */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-06-17 13:48:39 -04:00
|
|
|
return ret;
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
2009-04-15 14:04:23 -04:00
|
|
|
void
|
|
|
|
Editor::get_onscreen_tracks (TrackViewList& tvl)
|
|
|
|
{
|
2011-10-07 16:09:01 -04:00
|
|
|
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
|
2013-04-04 00:32:52 -04:00
|
|
|
if ((*i)->y_position() < _visible_canvas_height) {
|
2011-10-07 16:09:01 -04:00
|
|
|
tvl.push_back (*i);
|
|
|
|
}
|
|
|
|
}
|
2009-04-15 14:04:23 -04:00
|
|
|
}
|
|
|
|
|
2009-06-25 16:58:32 -04:00
|
|
|
/** Call a slot for a given `basis' track and also for any track that is in the same
|
|
|
|
* active route group with a particular set of properties.
|
|
|
|
*
|
2007-10-06 12:24:08 -04:00
|
|
|
* @param sl Slot to call.
|
|
|
|
* @param basis Basis track.
|
2009-06-25 16:58:32 -04:00
|
|
|
* @param prop Properties that active edit groups must share to be included in the map.
|
2007-10-06 12:24:08 -04:00
|
|
|
*/
|
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
void
|
2021-06-04 10:36:53 -04:00
|
|
|
Editor::mapover_grouped_routes (sigc::slot<void, RouteUI&> sl, RouteUI* basis, PBD::PropertyID prop) const
|
2007-01-28 12:44:13 -05:00
|
|
|
{
|
2021-01-25 17:52:39 -05:00
|
|
|
set<RouteUI*> routes;
|
2009-12-13 14:09:52 -05:00
|
|
|
|
2021-06-08 13:43:18 -04:00
|
|
|
routes.insert(basis);
|
|
|
|
|
2021-01-25 17:52:39 -05:00
|
|
|
RouteGroup* group = basis->route()->route_group();
|
2010-07-06 07:34:00 -04:00
|
|
|
|
2017-12-11 18:13:12 -05:00
|
|
|
if (group && group->enabled_property(prop) && group->enabled_property (Properties::active.property_id)) {
|
2009-12-13 14:09:52 -05:00
|
|
|
|
|
|
|
/* the basis is a member of an active route group, with the appropriate
|
2021-01-25 17:52:39 -05:00
|
|
|
* properties; find other members */
|
2009-12-13 14:09:52 -05:00
|
|
|
|
|
|
|
for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
|
2021-01-25 17:52:39 -05:00
|
|
|
RouteUI* v = dynamic_cast<RouteUI*> (*i);
|
2021-06-08 13:43:18 -04:00
|
|
|
if ( v && (v->route() != basis->route()) && v->route()->route_group() == group) {
|
2021-01-25 17:52:39 -05:00
|
|
|
routes.insert (v);
|
2009-12-13 14:09:52 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-10-06 12:24:08 -04:00
|
|
|
|
|
|
|
/* call the slots */
|
2021-06-04 10:36:53 -04:00
|
|
|
for (set<RouteUI*>::iterator i = routes.begin(); i != routes.end(); ++i) {
|
|
|
|
sl (**i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::mapover_armed_routes (sigc::slot<void, RouteUI&> sl) const
|
|
|
|
{
|
|
|
|
set<RouteUI*> routes;
|
|
|
|
for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
|
|
|
|
RouteUI* v = dynamic_cast<RouteUI*> (*i);
|
|
|
|
if (v && v->route()->is_track()) {
|
|
|
|
if ( v->track()->rec_enable_control()->get_value()) {
|
|
|
|
routes.insert (v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (set<RouteUI*>::iterator i = routes.begin(); i != routes.end(); ++i) {
|
|
|
|
sl (**i);
|
|
|
|
}
|
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2021-06-04 10:36:53 -04:00
|
|
|
void
|
|
|
|
Editor::mapover_selected_routes (sigc::slot<void, RouteUI&> sl) const
|
|
|
|
{
|
|
|
|
set<RouteUI*> routes;
|
|
|
|
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
|
|
|
|
RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
|
|
|
|
if (r) {
|
|
|
|
routes.insert (r);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (set<RouteUI*>::iterator i = routes.begin(); i != routes.end(); ++i) {
|
|
|
|
sl (**i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::mapover_all_routes (sigc::slot<void, RouteUI&> sl) const
|
|
|
|
{
|
|
|
|
set<RouteUI*> routes;
|
|
|
|
for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
|
|
|
|
RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
|
|
|
|
if (r) {
|
|
|
|
routes.insert (r);
|
|
|
|
}
|
|
|
|
}
|
2021-01-25 17:52:39 -05:00
|
|
|
for (set<RouteUI*>::iterator i = routes.begin(); i != routes.end(); ++i) {
|
2021-06-04 10:36:53 -04:00
|
|
|
sl (**i);
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-10 14:20:15 -05:00
|
|
|
/** Call a slot for a given `basis' track and also for any track that is in the same
|
|
|
|
* active route group with a particular set of properties.
|
|
|
|
*
|
|
|
|
* @param sl Slot to call.
|
|
|
|
* @param basis Basis track.
|
|
|
|
* @param prop Properties that active edit groups must share to be included in the map.
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::mapover_tracks_with_unique_playlists (sigc::slot<void, RouteTimeAxisView&, uint32_t> sl, TimeAxisView* basis, PBD::PropertyID prop) const
|
|
|
|
{
|
|
|
|
RouteTimeAxisView* route_basis = dynamic_cast<RouteTimeAxisView*> (basis);
|
2023-04-05 20:12:10 -04:00
|
|
|
PlaylistSet playlists;
|
2011-12-10 14:20:15 -05:00
|
|
|
|
|
|
|
if (route_basis == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
set<RouteTimeAxisView*> tracks;
|
|
|
|
tracks.insert (route_basis);
|
|
|
|
|
|
|
|
RouteGroup* group = route_basis->route()->route_group(); // could be null, not a problem
|
|
|
|
|
2017-12-11 18:13:12 -05:00
|
|
|
if (group && group->enabled_property(prop) && group->enabled_property (Properties::active.property_id)) {
|
2011-12-10 14:20:15 -05:00
|
|
|
|
|
|
|
/* the basis is a member of an active route group, with the appropriate
|
|
|
|
properties; find other members */
|
|
|
|
|
|
|
|
for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
|
|
|
|
RouteTimeAxisView* v = dynamic_cast<RouteTimeAxisView*> (*i);
|
|
|
|
|
|
|
|
if (v && v->route()->route_group() == group) {
|
2015-10-05 10:17:49 -04:00
|
|
|
|
2023-02-16 18:33:28 -05:00
|
|
|
std::shared_ptr<Track> t = v->track();
|
2011-12-10 14:20:15 -05:00
|
|
|
if (t) {
|
|
|
|
if (playlists.insert (t->playlist()).second) {
|
|
|
|
/* haven't seen this playlist yet */
|
|
|
|
tracks.insert (v);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* not actually a "Track", but a timeaxis view that
|
|
|
|
we should mapover anyway.
|
|
|
|
*/
|
|
|
|
tracks.insert (v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* call the slots */
|
|
|
|
uint32_t const sz = tracks.size ();
|
|
|
|
|
|
|
|
for (set<RouteTimeAxisView*>::iterator i = tracks.begin(); i != tracks.end(); ++i) {
|
|
|
|
sl (**i, sz);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-03 16:30:25 -04:00
|
|
|
void
|
|
|
|
Editor::mapover_all_tracks_with_unique_playlists (sigc::slot<void, RouteTimeAxisView&, uint32_t> sl) const
|
|
|
|
{
|
2023-04-05 20:12:10 -04:00
|
|
|
PlaylistSet playlists;
|
2021-06-03 16:30:25 -04:00
|
|
|
|
|
|
|
set<RouteTimeAxisView*> tracks;
|
|
|
|
|
|
|
|
for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
|
|
|
|
RouteTimeAxisView* v = dynamic_cast<RouteTimeAxisView*> (*i);
|
|
|
|
|
2022-06-22 16:22:52 -04:00
|
|
|
if (!v) {
|
|
|
|
/* Ignore VCAs */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-02-16 18:33:28 -05:00
|
|
|
std::shared_ptr<Track> t = v->track();
|
2021-06-03 16:30:25 -04:00
|
|
|
if (t) {
|
|
|
|
if (playlists.insert (t->playlist()).second) {
|
|
|
|
/* haven't seen this playlist yet */
|
|
|
|
tracks.insert (v);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* not actually a "Track", but a timeaxis view that
|
|
|
|
we should mapover anyway.
|
|
|
|
*/
|
|
|
|
tracks.insert (v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* call the slots */
|
|
|
|
uint32_t const sz = tracks.size ();
|
|
|
|
|
|
|
|
for (set<RouteTimeAxisView*>::iterator i = tracks.begin(); i != tracks.end(); ++i) {
|
|
|
|
sl (**i, sz);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
void
|
2009-07-21 11:55:17 -04:00
|
|
|
Editor::mapped_get_equivalent_regions (RouteTimeAxisView& tv, uint32_t, RegionView * basis, vector<RegionView*>* all_equivs) const
|
2007-01-28 12:44:13 -05:00
|
|
|
{
|
2023-02-16 18:33:28 -05:00
|
|
|
std::shared_ptr<Playlist> pl;
|
|
|
|
vector<std::shared_ptr<Region> > results;
|
2007-01-28 12:44:13 -05:00
|
|
|
RegionView* marv;
|
2023-02-16 18:33:28 -05:00
|
|
|
std::shared_ptr<Track> tr;
|
2007-01-28 12:44:13 -05:00
|
|
|
|
2010-04-21 16:42:22 -04:00
|
|
|
if ((tr = tv.track()) == 0) {
|
2007-01-28 12:44:13 -05:00
|
|
|
/* bus */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-08-07 10:12:56 -04:00
|
|
|
if (basis->region()->is_explicitly_ungrouped ()) {
|
|
|
|
/* this region is explicitly ungrouped; no need to check further */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (&tv == &basis->get_time_axis_view () && basis->region()->is_implicitly_ungrouped ()) {
|
|
|
|
/* fallback to region-equivalence: we do not check for equivalent regions in the same track as the basis */
|
2007-01-28 12:44:13 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-04-21 16:42:22 -04:00
|
|
|
if ((pl = tr->playlist()) != 0) {
|
2007-01-28 12:44:13 -05:00
|
|
|
pl->get_equivalent_regions (basis->region(), results);
|
|
|
|
}
|
|
|
|
|
2023-02-16 18:33:28 -05:00
|
|
|
for (vector<std::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
|
2009-07-09 13:58:13 -04:00
|
|
|
if ((marv = tv.view()->find_view (*ir)) != 0) {
|
2007-01-28 12:44:13 -05:00
|
|
|
all_equivs->push_back (marv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-02-18 08:59:49 -05:00
|
|
|
Editor::get_equivalent_regions (RegionView* basis, vector<RegionView*>& equivalent_regions, PBD::PropertyID property) const
|
2007-01-28 12:44:13 -05:00
|
|
|
{
|
2023-08-07 10:12:56 -04:00
|
|
|
if (basis->region()->is_explicitly_grouped ()) {
|
|
|
|
/* if the user made an explicit region group, it can span tracks outside of the track-group */
|
|
|
|
mapover_all_tracks_with_unique_playlists (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), basis, &equivalent_regions));
|
|
|
|
} else {
|
|
|
|
mapover_tracks_with_unique_playlists (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), basis, &equivalent_regions), &basis->get_time_axis_view(), property);
|
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
/* add clicked regionview since we skipped all other regions in the same track as the one it was in */
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
equivalent_regions.push_back (basis);
|
|
|
|
}
|
|
|
|
|
2021-06-03 16:30:25 -04:00
|
|
|
void
|
|
|
|
Editor::get_all_equivalent_regions (RegionView* basis, vector<RegionView*>& equivalent_regions) const
|
|
|
|
{
|
|
|
|
mapover_all_tracks_with_unique_playlists (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), basis, &equivalent_regions));
|
|
|
|
|
|
|
|
/* add clicked regionview since we skipped all other regions in the same track as the one it was in */
|
|
|
|
|
|
|
|
equivalent_regions.push_back (basis);
|
|
|
|
}
|
|
|
|
|
2009-06-25 16:58:32 -04:00
|
|
|
RegionSelection
|
2010-02-18 08:59:49 -05:00
|
|
|
Editor::get_equivalent_regions (RegionSelection & basis, PBD::PropertyID prop) const
|
2009-06-25 16:58:32 -04:00
|
|
|
{
|
|
|
|
RegionSelection equivalent;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2009-06-25 16:58:32 -04:00
|
|
|
for (RegionSelection::const_iterator i = basis.begin(); i != basis.end(); ++i) {
|
|
|
|
|
|
|
|
vector<RegionView*> eq;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2011-12-10 14:20:15 -05:00
|
|
|
mapover_tracks_with_unique_playlists (
|
2009-12-11 18:29:48 -05:00
|
|
|
sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), *i, &eq),
|
2011-10-07 16:09:01 -04:00
|
|
|
&(*i)->get_time_axis_view(), prop);
|
2009-06-25 16:58:32 -04:00
|
|
|
|
|
|
|
for (vector<RegionView*>::iterator j = eq.begin(); j != eq.end(); ++j) {
|
|
|
|
equivalent.add (*j);
|
|
|
|
}
|
|
|
|
|
|
|
|
equivalent.add (*i);
|
|
|
|
}
|
|
|
|
|
|
|
|
return equivalent;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
bool
|
2012-01-30 17:53:22 -05:00
|
|
|
Editor::set_selected_regionview_from_click (bool press, Selection::Operation op)
|
2007-01-28 12:44:13 -05:00
|
|
|
{
|
|
|
|
vector<RegionView*> all_equivalent_regions;
|
|
|
|
bool commit = false;
|
|
|
|
|
|
|
|
if (!clicked_regionview || !clicked_routeview) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (press) {
|
|
|
|
button_release_can_deselect = false;
|
2009-10-14 12:10:01 -04:00
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
|
|
|
|
if (op == Selection::Toggle || op == Selection::Set) {
|
|
|
|
|
|
|
|
switch (op) {
|
|
|
|
case Selection::Toggle:
|
2008-01-10 16:20:59 -05:00
|
|
|
if (selection->selected (clicked_regionview)) {
|
2007-01-28 12:44:13 -05:00
|
|
|
if (press) {
|
|
|
|
|
|
|
|
/* whatever was clicked was selected already; do nothing here but allow
|
|
|
|
the button release to deselect it
|
|
|
|
*/
|
|
|
|
|
|
|
|
button_release_can_deselect = true;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
if (button_release_can_deselect) {
|
|
|
|
|
2021-06-03 17:35:09 -04:00
|
|
|
/* just remove this one region
|
|
|
|
* (or all equivalent regions
|
|
|
|
* for RippleAll, but only on a
|
|
|
|
* permitted button release
|
|
|
|
*/
|
|
|
|
|
2022-03-14 20:14:43 -04:00
|
|
|
if (should_ripple_all()) {
|
2021-06-03 17:35:09 -04:00
|
|
|
get_all_equivalent_regions (clicked_regionview, all_equivalent_regions);
|
|
|
|
selection->remove (all_equivalent_regions);
|
|
|
|
} else {
|
|
|
|
selection->remove (clicked_regionview);
|
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
commit = true;
|
|
|
|
|
|
|
|
/* no more deselect action on button release till a new press
|
|
|
|
finds an already selected object.
|
|
|
|
*/
|
|
|
|
|
|
|
|
button_release_can_deselect = false;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
if (press) {
|
|
|
|
|
2022-03-14 20:14:43 -04:00
|
|
|
if (should_ripple_all()) {
|
2021-06-03 16:30:25 -04:00
|
|
|
get_all_equivalent_regions (clicked_regionview, all_equivalent_regions);
|
2007-01-28 12:44:13 -05:00
|
|
|
} else {
|
2021-06-03 16:30:25 -04:00
|
|
|
if (selection->selected (clicked_routeview)) {
|
|
|
|
get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::group_select.property_id);
|
|
|
|
} else {
|
|
|
|
all_equivalent_regions.push_back (clicked_regionview);
|
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* add all the equivalent regions, but only on button press */
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
if (!all_equivalent_regions.empty()) {
|
|
|
|
commit = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
selection->add (all_equivalent_regions);
|
2009-10-14 12:10:01 -04:00
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
break;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
case Selection::Set:
|
2008-01-10 16:20:59 -05:00
|
|
|
if (!selection->selected (clicked_regionview)) {
|
2022-03-14 20:14:43 -04:00
|
|
|
if (should_ripple_all()) {
|
2021-06-03 16:30:25 -04:00
|
|
|
get_all_equivalent_regions (clicked_regionview, all_equivalent_regions);
|
|
|
|
} else {
|
|
|
|
get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::group_select.property_id);
|
|
|
|
}
|
2009-06-21 15:59:56 -04:00
|
|
|
selection->set (all_equivalent_regions);
|
2007-01-28 12:44:13 -05:00
|
|
|
commit = true;
|
|
|
|
} else {
|
2014-08-12 15:40:43 -04:00
|
|
|
/* clicked on an already selected region */
|
|
|
|
if (press)
|
|
|
|
goto out;
|
|
|
|
else {
|
2015-01-16 12:17:09 -05:00
|
|
|
if (selection->regions.size() > 1) {
|
|
|
|
/* collapse region selection down to just this one region (and its equivalents) */
|
2022-03-14 20:14:43 -04:00
|
|
|
if (should_ripple_all()) {
|
2021-06-03 16:30:25 -04:00
|
|
|
get_all_equivalent_regions (clicked_regionview, all_equivalent_regions);
|
|
|
|
} else {
|
|
|
|
get_equivalent_regions(clicked_regionview, all_equivalent_regions, ARDOUR::Properties::group_select.property_id);
|
|
|
|
}
|
2015-01-16 12:17:09 -05:00
|
|
|
selection->set(all_equivalent_regions);
|
|
|
|
commit = true;
|
|
|
|
}
|
2014-08-12 15:40:43 -04:00
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
/* silly compiler */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (op == Selection::Extend) {
|
|
|
|
|
|
|
|
list<Selectable*> results;
|
2020-10-19 14:37:54 -04:00
|
|
|
timepos_t last_pos;
|
|
|
|
timepos_t first_pos;
|
2008-01-10 16:20:59 -05:00
|
|
|
bool same_track = false;
|
2007-01-28 12:44:13 -05:00
|
|
|
|
|
|
|
/* 1. find the last selected regionview in the track that was clicked in */
|
|
|
|
|
2020-12-03 23:34:48 -05:00
|
|
|
const Temporal::TimeDomain time_domain = (selection->regions.empty() ? Temporal::AudioTime : selection->regions.front()->region()->position().time_domain());
|
|
|
|
last_pos = timepos_t (time_domain);
|
|
|
|
first_pos = timepos_t::max (time_domain);
|
2007-01-28 12:44:13 -05:00
|
|
|
|
|
|
|
for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
|
2009-07-09 13:58:13 -04:00
|
|
|
if (&(*x)->get_time_axis_view() == &clicked_regionview->get_time_axis_view()) {
|
2007-01-28 12:44:13 -05:00
|
|
|
|
2020-10-19 14:37:54 -04:00
|
|
|
if ((*x)->region()->nt_last() > last_pos) {
|
|
|
|
last_pos = (*x)->region()->nt_last();
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
2020-11-30 12:59:17 -05:00
|
|
|
if ((*x)->region()->position() < first_pos) {
|
|
|
|
first_pos = (*x)->region()->position();
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
2008-01-10 16:20:59 -05:00
|
|
|
|
|
|
|
same_track = true;
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
if (same_track) {
|
2007-01-28 12:44:13 -05:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
/* 2. figure out the boundaries for our search for new objects */
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2020-10-19 14:37:54 -04:00
|
|
|
switch (clicked_regionview->region()->coverage (first_pos, last_pos)) {
|
|
|
|
case Temporal::OverlapNone:
|
2020-11-30 12:59:17 -05:00
|
|
|
if (last_pos < clicked_regionview->region()->position()) {
|
2020-10-19 14:37:54 -04:00
|
|
|
first_pos = last_pos;
|
|
|
|
last_pos = clicked_regionview->region()->nt_last();
|
2008-01-10 16:20:59 -05:00
|
|
|
} else {
|
2020-10-19 14:37:54 -04:00
|
|
|
last_pos = first_pos;
|
2020-11-30 12:59:17 -05:00
|
|
|
first_pos = clicked_regionview->region()->position();
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
|
|
|
break;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2020-10-19 14:37:54 -04:00
|
|
|
case Temporal::OverlapExternal:
|
2020-11-30 12:59:17 -05:00
|
|
|
if (last_pos < clicked_regionview->region()->position()) {
|
2020-10-19 14:37:54 -04:00
|
|
|
first_pos = last_pos;
|
|
|
|
last_pos = clicked_regionview->region()->nt_last();
|
2008-01-10 16:20:59 -05:00
|
|
|
} else {
|
2020-10-19 14:37:54 -04:00
|
|
|
last_pos = first_pos;
|
2020-11-30 12:59:17 -05:00
|
|
|
first_pos = clicked_regionview->region()->position();
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
|
|
|
break;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2020-10-19 14:37:54 -04:00
|
|
|
case Temporal::OverlapInternal:
|
2020-11-30 12:59:17 -05:00
|
|
|
if (last_pos < clicked_regionview->region()->position()) {
|
2020-10-19 14:37:54 -04:00
|
|
|
first_pos = last_pos;
|
|
|
|
last_pos = clicked_regionview->region()->nt_last();
|
2008-01-10 16:20:59 -05:00
|
|
|
} else {
|
2020-10-19 14:37:54 -04:00
|
|
|
last_pos = first_pos;
|
2020-11-30 12:59:17 -05:00
|
|
|
first_pos = clicked_regionview->region()->position();
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
|
|
|
break;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2020-10-19 14:37:54 -04:00
|
|
|
case Temporal::OverlapStart:
|
|
|
|
case Temporal::OverlapEnd:
|
2008-01-10 16:20:59 -05:00
|
|
|
/* nothing to do except add clicked region to selection, since it
|
|
|
|
overlaps with the existing selection in this track.
|
|
|
|
*/
|
|
|
|
break;
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
} else {
|
2007-01-28 12:44:13 -05:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
/* click in a track that has no regions selected, so extend vertically
|
|
|
|
to pick out all regions that are defined by the existing selection
|
|
|
|
plus this one.
|
|
|
|
*/
|
2009-10-14 12:10:01 -04:00
|
|
|
|
|
|
|
|
2020-11-30 12:59:17 -05:00
|
|
|
first_pos = clicked_regionview->region()->position();
|
2020-10-19 14:37:54 -04:00
|
|
|
last_pos = clicked_regionview->region()->nt_last();
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
|
2020-11-30 12:59:17 -05:00
|
|
|
if ((*i)->region()->position() < first_pos) {
|
|
|
|
first_pos = (*i)->region()->position();
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
2020-11-30 12:59:17 -05:00
|
|
|
if ((*i)->region()->end() > last_pos) {
|
2020-10-19 14:37:54 -04:00
|
|
|
last_pos = (*i)->region()->nt_last();
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 2. find all the tracks we should select in */
|
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
set<RouteTimeAxisView*> relevant_tracks;
|
2008-01-10 16:20:59 -05:00
|
|
|
|
2022-03-14 20:14:43 -04:00
|
|
|
if (should_ripple_all()) {
|
2021-06-03 16:52:17 -04:00
|
|
|
for (TrackSelection::iterator i = track_views.begin(); i != track_views.end(); ++i) {
|
|
|
|
RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
|
|
|
|
if (r) {
|
|
|
|
relevant_tracks.insert (r);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
|
|
|
|
RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
|
|
|
|
if (r) {
|
|
|
|
relevant_tracks.insert (r);
|
|
|
|
}
|
2009-12-13 14:09:52 -05:00
|
|
|
}
|
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2009-12-13 14:09:52 -05:00
|
|
|
set<RouteTimeAxisView*> already_in_selection;
|
2008-01-10 16:20:59 -05:00
|
|
|
|
|
|
|
if (relevant_tracks.empty()) {
|
2007-01-28 12:44:13 -05:00
|
|
|
|
2009-12-13 14:09:52 -05:00
|
|
|
/* no tracks selected .. thus .. if the
|
|
|
|
regionview we're in isn't selected
|
|
|
|
(i.e. we're about to extend to it), then
|
|
|
|
find all tracks between the this one and
|
|
|
|
any selected ones.
|
2007-01-28 12:44:13 -05:00
|
|
|
*/
|
2008-01-10 16:20:59 -05:00
|
|
|
|
2010-09-22 08:37:48 -04:00
|
|
|
if (!selection->selected (clicked_regionview)) {
|
2008-01-10 16:20:59 -05:00
|
|
|
|
2010-09-22 08:37:48 -04:00
|
|
|
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&clicked_regionview->get_time_axis_view());
|
2008-01-10 16:20:59 -05:00
|
|
|
|
|
|
|
if (rtv) {
|
|
|
|
|
|
|
|
/* add this track to the ones we will search */
|
|
|
|
|
|
|
|
relevant_tracks.insert (rtv);
|
|
|
|
|
|
|
|
/* find the track closest to this one that
|
|
|
|
already a selected region.
|
|
|
|
*/
|
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
RouteTimeAxisView* closest = 0;
|
2008-01-10 16:20:59 -05:00
|
|
|
int distance = INT_MAX;
|
2016-06-03 15:15:30 -04:00
|
|
|
int key = rtv->route()->presentation_info().order ();
|
2008-01-10 16:20:59 -05:00
|
|
|
|
|
|
|
for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
|
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(&(*x)->get_time_axis_view());
|
2008-01-10 16:20:59 -05:00
|
|
|
|
|
|
|
if (artv && artv != rtv) {
|
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
pair<set<RouteTimeAxisView*>::iterator,bool> result;
|
2008-01-10 16:20:59 -05:00
|
|
|
|
|
|
|
result = already_in_selection.insert (artv);
|
|
|
|
|
|
|
|
if (result.second) {
|
|
|
|
/* newly added to already_in_selection */
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2016-06-03 15:15:30 -04:00
|
|
|
int d = artv->route()->presentation_info().order ();
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
d -= key;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
if (abs (d) < distance) {
|
|
|
|
distance = abs (d);
|
|
|
|
closest = artv;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
if (closest) {
|
|
|
|
|
|
|
|
/* now add all tracks between that one and this one */
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2016-06-03 15:15:30 -04:00
|
|
|
int okey = closest->route()->presentation_info().order ();
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
if (okey > key) {
|
|
|
|
swap (okey, key);
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
for (TrackViewList::iterator x = track_views.begin(); x != track_views.end(); ++x) {
|
2009-07-09 13:58:13 -04:00
|
|
|
RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(*x);
|
2008-01-10 16:20:59 -05:00
|
|
|
if (artv && artv != rtv) {
|
|
|
|
|
2016-06-03 15:15:30 -04:00
|
|
|
int k = artv->route()->presentation_info().order ();
|
2008-01-10 16:20:59 -05:00
|
|
|
|
|
|
|
if (k >= okey && k <= key) {
|
|
|
|
|
|
|
|
/* in range but don't add it if
|
|
|
|
it already has tracks selected.
|
|
|
|
this avoids odd selection
|
|
|
|
behaviour that feels wrong.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (find (already_in_selection.begin(),
|
2011-10-07 16:09:01 -04:00
|
|
|
already_in_selection.end(),
|
|
|
|
artv) == already_in_selection.end()) {
|
2008-01-10 16:20:59 -05:00
|
|
|
|
|
|
|
relevant_tracks.insert (artv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
/* 3. find all selectable objects (regionviews in this case) between that one and the end of the
|
2011-10-07 16:09:01 -04:00
|
|
|
one that was clicked.
|
2007-01-28 12:44:13 -05:00
|
|
|
*/
|
|
|
|
|
2009-07-09 13:58:13 -04:00
|
|
|
for (set<RouteTimeAxisView*>::iterator t = relevant_tracks.begin(); t != relevant_tracks.end(); ++t) {
|
2020-10-19 14:37:54 -04:00
|
|
|
(*t)->get_selectables (first_pos, last_pos, -1.0, -1.0, results);
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-01-10 16:20:59 -05:00
|
|
|
/* 4. convert to a vector of regions */
|
2007-01-28 12:44:13 -05:00
|
|
|
|
|
|
|
vector<RegionView*> regions;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
for (list<Selectable*>::iterator x = results.begin(); x != results.end(); ++x) {
|
|
|
|
RegionView* arv;
|
|
|
|
|
|
|
|
if ((arv = dynamic_cast<RegionView*>(*x)) != 0) {
|
|
|
|
regions.push_back (arv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!regions.empty()) {
|
|
|
|
selection->add (regions);
|
|
|
|
commit = true;
|
2016-08-19 11:34:53 -04:00
|
|
|
} else if (selection->regions.empty() && !selection->selected (clicked_regionview)) {
|
|
|
|
/* ensure that at least the clicked regionview is selected. */
|
|
|
|
selection->set (clicked_regionview);
|
|
|
|
commit = true;
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
2016-08-19 11:34:53 -04:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
2011-10-07 16:09:01 -04:00
|
|
|
out:
|
2007-01-28 12:44:13 -05:00
|
|
|
return commit;
|
|
|
|
}
|
|
|
|
|
2020-05-01 19:37:27 -04:00
|
|
|
void
|
|
|
|
Editor::set_selected_midi_region_view (MidiRegionView& mrv)
|
|
|
|
{
|
|
|
|
/* clear note selection in all currently selected MidiRegionViews */
|
2020-05-05 20:00:05 -04:00
|
|
|
|
|
|
|
if (get_selection().regions.contains (&mrv) && get_selection().regions.size() == 1) {
|
|
|
|
/* Nothing to do */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-05-01 19:37:27 -04:00
|
|
|
midi_action (&MidiRegionView::clear_note_selection);
|
|
|
|
get_selection().set (&mrv);
|
|
|
|
}
|
|
|
|
|
2017-02-23 16:31:03 -05:00
|
|
|
void
|
|
|
|
Editor::set_selection (std::list<Selectable*> s, Selection::Operation op)
|
|
|
|
{
|
|
|
|
if (s.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
begin_reversible_selection_op (X_("set selection"));
|
|
|
|
switch (op) {
|
|
|
|
case Selection::Toggle:
|
|
|
|
selection->toggle (s);
|
|
|
|
break;
|
|
|
|
case Selection::Set:
|
|
|
|
selection->set (s);
|
|
|
|
break;
|
|
|
|
case Selection::Extend:
|
|
|
|
selection->add (s);
|
|
|
|
break;
|
|
|
|
case Selection::Add:
|
|
|
|
selection->add (s);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
commit_reversible_selection_op () ;
|
|
|
|
}
|
2008-01-10 16:20:59 -05:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
void
|
2023-02-16 18:33:28 -05:00
|
|
|
Editor::set_selected_regionview_from_region_list (std::shared_ptr<Region> region, Selection::Operation op)
|
2007-01-28 12:44:13 -05:00
|
|
|
{
|
2021-06-04 14:24:13 -04:00
|
|
|
vector<RegionView*> regionviews;
|
2007-01-28 12:44:13 -05:00
|
|
|
|
2021-06-04 14:24:13 -04:00
|
|
|
get_regionview_corresponding_to (region, regionviews);
|
2008-01-10 16:20:59 -05:00
|
|
|
|
2021-06-04 14:24:13 -04:00
|
|
|
if (regionviews.empty()) {
|
2008-01-10 16:20:59 -05:00
|
|
|
return;
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
2008-01-10 16:20:59 -05:00
|
|
|
|
2015-03-25 08:31:23 -04:00
|
|
|
begin_reversible_selection_op (X_("set selected regions"));
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
switch (op) {
|
|
|
|
case Selection::Toggle:
|
|
|
|
/* XXX this is not correct */
|
2021-06-04 14:24:13 -04:00
|
|
|
selection->toggle (regionviews);
|
2007-01-28 12:44:13 -05:00
|
|
|
break;
|
|
|
|
case Selection::Set:
|
2021-06-04 14:24:13 -04:00
|
|
|
selection->set (regionviews);
|
2007-01-28 12:44:13 -05:00
|
|
|
break;
|
|
|
|
case Selection::Extend:
|
2021-06-04 14:24:13 -04:00
|
|
|
selection->add (regionviews);
|
2007-01-28 12:44:13 -05:00
|
|
|
break;
|
|
|
|
case Selection::Add:
|
2021-06-04 14:24:13 -04:00
|
|
|
selection->add (regionviews);
|
2007-01-28 12:44:13 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-12-22 08:30:23 -05:00
|
|
|
commit_reversible_selection_op () ;
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
2008-01-12 18:45:50 -05:00
|
|
|
bool
|
2023-02-16 18:33:28 -05:00
|
|
|
Editor::set_selected_regionview_from_map_event (GdkEventAny* /*ev*/, StreamView* sv, std::weak_ptr<Region> weak_r)
|
2008-01-12 18:45:50 -05:00
|
|
|
{
|
|
|
|
RegionView* rv;
|
2023-02-16 18:33:28 -05:00
|
|
|
std::shared_ptr<Region> r (weak_r.lock());
|
2008-01-12 18:45:50 -05:00
|
|
|
|
|
|
|
if (!r) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((rv = sv->find_view (r)) == 0) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-10-14 12:10:01 -04:00
|
|
|
/* don't reset the selection if its something other than
|
2008-01-12 18:45:50 -05:00
|
|
|
a single other region.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (selection->regions.size() > 1) {
|
|
|
|
return true;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2015-03-25 08:31:23 -04:00
|
|
|
begin_reversible_selection_op (X_("set selected regions"));
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2008-01-12 18:45:50 -05:00
|
|
|
selection->set (rv);
|
|
|
|
|
2014-12-22 08:30:23 -05:00
|
|
|
commit_reversible_selection_op () ;
|
2008-01-12 18:45:50 -05:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
void
|
2017-05-05 07:31:49 -04:00
|
|
|
Editor::presentation_info_changed (PropertyChange const & what_changed)
|
2007-01-28 12:44:13 -05:00
|
|
|
{
|
2017-08-07 11:34:03 -04:00
|
|
|
uint32_t n_tracks = 0;
|
|
|
|
uint32_t n_busses = 0;
|
|
|
|
uint32_t n_vcas = 0;
|
|
|
|
uint32_t n_routes = 0;
|
|
|
|
uint32_t n_stripables = 0;
|
|
|
|
|
2017-05-05 07:31:49 -04:00
|
|
|
/* We cannot ensure ordering of the handlers for
|
|
|
|
* PresentationInfo::Changed, so we have to do everything in order
|
|
|
|
* here, as a single handler.
|
|
|
|
*/
|
2017-02-26 12:22:39 -05:00
|
|
|
|
2017-06-17 09:49:01 -04:00
|
|
|
if (what_changed.contains (Properties::selected)) {
|
|
|
|
for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
|
|
|
|
(*i)->set_selected (false);
|
|
|
|
(*i)->hide_selection ();
|
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
2017-05-05 07:31:49 -04:00
|
|
|
/* STEP 1: set the GUI selection state (in which TimeAxisViews for the
|
|
|
|
* currently selected stripable/controllable duples are found and added
|
|
|
|
*/
|
2012-04-12 10:34:03 -04:00
|
|
|
|
2017-05-05 07:31:49 -04:00
|
|
|
selection->core_selection_changed (what_changed);
|
2010-08-26 19:25:44 -04:00
|
|
|
|
2017-05-05 07:31:49 -04:00
|
|
|
/* STEP 2: update TimeAxisView's knowledge of their selected state
|
|
|
|
*/
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2017-05-05 07:31:49 -04:00
|
|
|
if (what_changed.contains (Properties::selected)) {
|
2012-04-12 10:34:03 -04:00
|
|
|
|
2017-05-05 07:31:49 -04:00
|
|
|
StripableNotificationListPtr stripables (new StripableNotificationList);
|
2012-04-12 10:34:03 -04:00
|
|
|
|
2017-05-05 07:31:49 -04:00
|
|
|
switch (selection->tracks.size()) {
|
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
set_selected_mixer_strip (*(selection->tracks.back()));
|
2017-10-21 11:27:03 -04:00
|
|
|
if (!_track_selection_change_without_scroll && !_editor_track_selection_change_without_scroll) {
|
2017-05-05 07:31:49 -04:00
|
|
|
ensure_time_axis_view_is_visible (*(selection->tracks.back()), false);
|
2012-04-12 10:34:03 -04:00
|
|
|
}
|
2017-05-05 07:31:49 -04:00
|
|
|
break;
|
2012-04-12 10:34:03 -04:00
|
|
|
}
|
2008-03-17 16:54:03 -04:00
|
|
|
|
2017-05-05 07:31:49 -04:00
|
|
|
CoreSelection::StripableAutomationControls sc;
|
|
|
|
_session->selection().get_stripables (sc);
|
2012-04-12 10:34:03 -04:00
|
|
|
|
2017-05-05 07:31:49 -04:00
|
|
|
for (CoreSelection::StripableAutomationControls::const_iterator i = sc.begin(); i != sc.end(); ++i) {
|
2017-02-16 04:29:32 -05:00
|
|
|
|
2017-05-05 07:31:49 -04:00
|
|
|
AxisView* av = axis_view_by_stripable ((*i).stripable);
|
2015-10-05 10:17:49 -04:00
|
|
|
|
2017-05-05 07:31:49 -04:00
|
|
|
if (!av) {
|
|
|
|
continue;
|
|
|
|
}
|
2015-09-20 14:03:09 -04:00
|
|
|
|
2017-08-07 11:34:03 -04:00
|
|
|
n_stripables++;
|
|
|
|
|
2023-02-16 18:33:28 -05:00
|
|
|
if (std::dynamic_pointer_cast<Track> ((*i).stripable)) {
|
2017-08-07 11:34:03 -04:00
|
|
|
n_tracks++;
|
|
|
|
n_routes++;
|
2023-02-16 18:33:28 -05:00
|
|
|
} else if (std::dynamic_pointer_cast<Route> ((*i).stripable)) {
|
2017-08-07 11:34:03 -04:00
|
|
|
n_busses++;
|
|
|
|
n_routes++;
|
2023-02-16 18:33:28 -05:00
|
|
|
} else if (std::dynamic_pointer_cast<VCA> ((*i).stripable)) {
|
2017-08-07 11:34:03 -04:00
|
|
|
n_vcas++;
|
|
|
|
}
|
|
|
|
|
2017-05-05 07:31:49 -04:00
|
|
|
TimeAxisView* tav = dynamic_cast<TimeAxisView*> (av);
|
2015-09-20 14:03:09 -04:00
|
|
|
|
2017-05-05 07:31:49 -04:00
|
|
|
if (!tav) {
|
2017-06-17 09:49:01 -04:00
|
|
|
assert (0);
|
2017-05-05 07:31:49 -04:00
|
|
|
continue; /* impossible */
|
|
|
|
}
|
2015-09-20 14:03:09 -04:00
|
|
|
|
2017-05-05 07:31:49 -04:00
|
|
|
if (!(*i).controllable) {
|
|
|
|
|
|
|
|
/* "parent" track selected */
|
|
|
|
tav->set_selected (true);
|
|
|
|
tav->reshow_selection (selection->time);
|
2015-09-20 14:03:09 -04:00
|
|
|
|
|
|
|
} else {
|
|
|
|
|
2017-05-05 07:31:49 -04:00
|
|
|
/* possibly a child */
|
|
|
|
|
|
|
|
TimeAxisView::Children c = tav->get_child_list ();
|
|
|
|
|
|
|
|
for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
|
|
|
|
|
2023-02-16 18:33:28 -05:00
|
|
|
std::shared_ptr<AutomationControl> control = (*j)->control ();
|
2017-05-05 07:31:49 -04:00
|
|
|
|
|
|
|
if (control != (*i).controllable) {
|
|
|
|
continue;
|
2015-09-20 14:03:09 -04:00
|
|
|
}
|
2017-05-05 07:31:49 -04:00
|
|
|
|
|
|
|
(*j)->set_selected (true);
|
|
|
|
(*j)->reshow_selection (selection->time);
|
2015-09-20 14:03:09 -04:00
|
|
|
}
|
|
|
|
}
|
2017-05-05 07:31:49 -04:00
|
|
|
|
|
|
|
stripables->push_back ((*i).stripable);
|
|
|
|
}
|
|
|
|
|
2017-08-07 11:34:03 -04:00
|
|
|
ActionManager::set_sensitive (ActionManager::stripable_selection_sensitive_actions, (n_stripables > 0));
|
|
|
|
ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, (n_tracks > 0));
|
|
|
|
ActionManager::set_sensitive (ActionManager::bus_selection_sensitive_actions, (n_busses > 0));
|
|
|
|
ActionManager::set_sensitive (ActionManager::route_selection_sensitive_actions, (n_routes > 0));
|
|
|
|
ActionManager::set_sensitive (ActionManager::vca_selection_sensitive_actions, (n_vcas > 0));
|
2017-05-05 07:31:49 -04:00
|
|
|
|
|
|
|
sensitize_the_right_region_actions (false);
|
|
|
|
|
|
|
|
/* STEP 4: notify control protocols */
|
|
|
|
|
2017-05-12 09:51:31 -04:00
|
|
|
ControlProtocolManager::instance().stripable_selection_changed (stripables);
|
2017-05-05 07:31:49 -04:00
|
|
|
|
|
|
|
if (sfbrowser && _session && !_session->deletion_in_progress()) {
|
|
|
|
uint32_t audio_track_cnt = 0;
|
|
|
|
uint32_t midi_track_cnt = 0;
|
|
|
|
|
|
|
|
for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
|
|
|
|
AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*x);
|
|
|
|
|
|
|
|
if (atv) {
|
|
|
|
if (atv->is_audio_track()) {
|
|
|
|
audio_track_cnt++;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*>(*x);
|
|
|
|
|
|
|
|
if (mtv) {
|
|
|
|
if (mtv->is_midi_track()) {
|
|
|
|
midi_track_cnt++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sfbrowser->reset (audio_track_cnt, midi_track_cnt);
|
2015-09-20 14:03:09 -04:00
|
|
|
}
|
2017-05-05 07:31:49 -04:00
|
|
|
}
|
2015-09-20 14:03:09 -04:00
|
|
|
|
2022-01-25 09:59:38 -05:00
|
|
|
/* STEP 4: update Editor::track_views */
|
2017-05-05 07:31:49 -04:00
|
|
|
|
|
|
|
PropertyChange soh;
|
|
|
|
|
|
|
|
soh.add (Properties::order);
|
|
|
|
soh.add (Properties::hidden);
|
|
|
|
|
|
|
|
if (what_changed.contains (soh)) {
|
2022-01-25 09:59:38 -05:00
|
|
|
queue_redisplay_track_views ();
|
2015-09-20 14:03:09 -04:00
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
2023-09-07 15:20:05 -04:00
|
|
|
void
|
|
|
|
Editor::update_section_box ()
|
|
|
|
{
|
|
|
|
if (selection->tracks.size() == 0 && selection->regions.size () == 0 && selection->time.length() != 0) {
|
|
|
|
_section_box->set_position (selection->time.start_time().samples(), selection->time.end_time().samples());
|
|
|
|
_section_box->show ();
|
|
|
|
} else {
|
|
|
|
_section_box->hide();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-11 10:39:45 -05:00
|
|
|
void
|
|
|
|
Editor::track_selection_changed ()
|
|
|
|
{
|
2018-02-26 20:40:24 -05:00
|
|
|
/* reset paste count, so the plaste location doesn't get incremented
|
2018-08-24 09:50:37 -04:00
|
|
|
* if we want to paste in the same place, but different track. */
|
2018-02-26 20:40:24 -05:00
|
|
|
paste_count = 0;
|
2018-03-27 09:30:34 -04:00
|
|
|
|
2018-02-11 10:39:45 -05:00
|
|
|
if ( _session->solo_selection_active() )
|
|
|
|
play_solo_selection(false);
|
2023-09-05 17:51:33 -04:00
|
|
|
|
|
|
|
update_selection_markers ();
|
2023-09-07 15:20:05 -04:00
|
|
|
update_section_box ();
|
2018-02-11 10:39:45 -05:00
|
|
|
}
|
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
void
|
|
|
|
Editor::time_selection_changed ()
|
|
|
|
{
|
2014-06-18 21:03:11 -04:00
|
|
|
/* XXX this is superficially inefficient. Hide the selection in all
|
|
|
|
* tracks, then show it in all selected tracks.
|
|
|
|
*
|
|
|
|
* However, if you investigate what this actually does, it isn't
|
|
|
|
* anywhere nearly as bad as it may appear. Remember: nothing is
|
|
|
|
* redrawn or even recomputed during these two loops - that only
|
|
|
|
* happens when we next render ...
|
|
|
|
*/
|
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
|
|
|
|
(*i)->hide_selection ();
|
|
|
|
}
|
|
|
|
|
2023-09-05 17:51:33 -04:00
|
|
|
update_selection_markers ();
|
2023-09-07 15:20:05 -04:00
|
|
|
update_section_box ();
|
|
|
|
|
2009-12-13 16:27:19 -05:00
|
|
|
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
|
|
|
|
(*i)->show_selection (selection->time);
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if (selection->time.empty()) {
|
|
|
|
ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
|
|
|
|
} else {
|
|
|
|
ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true);
|
|
|
|
}
|
2015-01-16 12:17:09 -05:00
|
|
|
|
2015-01-17 12:40:46 -05:00
|
|
|
/* propagate into backend, but only when there is no drag or we are at
|
|
|
|
* the end of a drag, otherwise this is too expensive (could case a
|
|
|
|
* locate per mouse motion event.
|
|
|
|
*/
|
2015-01-16 12:17:09 -05:00
|
|
|
|
2015-01-17 12:40:46 -05:00
|
|
|
if (_session && !_drags->active()) {
|
2015-01-16 12:17:09 -05:00
|
|
|
if (selection->time.length() != 0) {
|
2020-10-19 14:37:54 -04:00
|
|
|
_session->set_range_selection (selection->time.start_time(), selection->time.end_time());
|
2015-01-16 12:17:09 -05:00
|
|
|
} else {
|
|
|
|
_session->clear_range_selection ();
|
|
|
|
}
|
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
/** Set all region actions to have a given sensitivity */
|
2007-01-28 12:44:13 -05:00
|
|
|
void
|
2010-11-03 18:19:29 -04:00
|
|
|
Editor::sensitize_all_region_actions (bool s)
|
2007-01-28 12:44:13 -05:00
|
|
|
{
|
2010-11-03 18:19:29 -04:00
|
|
|
Glib::ListHandle<Glib::RefPtr<Action> > all = _region_actions->get_actions ();
|
2008-02-19 17:10:27 -05:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
for (Glib::ListHandle<Glib::RefPtr<Action> >::iterator i = all.begin(); i != all.end(); ++i) {
|
|
|
|
(*i)->set_sensitive (s);
|
|
|
|
}
|
2008-02-19 17:10:27 -05:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
_all_region_actions_sensitized = s;
|
|
|
|
}
|
2008-02-19 17:10:27 -05:00
|
|
|
|
2017-02-15 13:00:28 -05:00
|
|
|
/** Sensitize region-based actions.
|
2017-02-10 16:12:28 -05:00
|
|
|
*
|
2017-02-15 13:00:28 -05:00
|
|
|
* This method is called from whenever we leave the canvas, either by moving
|
|
|
|
* the pointer out of it, or by popping up a context menu. See
|
|
|
|
* Editor::{entered,left}_track_canvas() for details there.
|
2010-11-03 18:19:29 -04:00
|
|
|
*/
|
|
|
|
void
|
2017-02-15 13:50:51 -05:00
|
|
|
Editor::sensitize_the_right_region_actions (bool because_canvas_crossing)
|
2010-11-03 18:19:29 -04:00
|
|
|
{
|
2017-02-14 10:09:32 -05:00
|
|
|
bool have_selection = false;
|
|
|
|
bool have_entered = false;
|
|
|
|
bool have_edit_point = false;
|
2019-07-30 14:02:15 -04:00
|
|
|
bool have_selected_source = false;
|
2017-02-14 10:09:32 -05:00
|
|
|
RegionSelection rs;
|
|
|
|
|
2017-02-16 04:29:04 -05:00
|
|
|
// std::cerr << "STRRA: crossing ? " << because_canvas_crossing << " within ? " << within_track_canvas
|
|
|
|
// << std::endl;
|
|
|
|
|
2017-02-14 10:09:32 -05:00
|
|
|
if (!selection->regions.empty()) {
|
|
|
|
have_selection = true;
|
|
|
|
rs = selection->regions;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (entered_regionview) {
|
|
|
|
have_entered = true;
|
|
|
|
rs.add (entered_regionview);
|
|
|
|
}
|
|
|
|
|
2019-07-30 14:02:15 -04:00
|
|
|
if ( _sources->get_single_selection() ) {
|
|
|
|
have_selected_source = true;
|
|
|
|
}
|
|
|
|
|
2017-02-15 13:00:28 -05:00
|
|
|
if (rs.empty() && !selection->tracks.empty()) {
|
|
|
|
|
2017-02-16 04:29:04 -05:00
|
|
|
/* no selected regions, but some selected tracks.
|
2017-02-15 13:00:28 -05:00
|
|
|
*/
|
|
|
|
|
2017-02-16 04:29:04 -05:00
|
|
|
if (_edit_point == EditAtMouse) {
|
|
|
|
if (!within_track_canvas) {
|
|
|
|
/* pointer is not in canvas, so edit point is meaningless */
|
2017-02-15 13:00:28 -05:00
|
|
|
have_edit_point = false;
|
|
|
|
} else {
|
2017-02-16 04:29:04 -05:00
|
|
|
/* inside canvas. we don't know where the edit
|
|
|
|
point will be when an action is invoked, but
|
|
|
|
assume it could intersect with a region.
|
|
|
|
*/
|
|
|
|
have_edit_point = true;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
RegionSelection at_edit_point;
|
2020-10-19 14:37:54 -04:00
|
|
|
timepos_t const where = get_preferred_edit_position (Editing::EDIT_IGNORE_NONE, false, !within_track_canvas);
|
2017-02-16 04:29:04 -05:00
|
|
|
get_regions_at (at_edit_point, where, selection->tracks);
|
|
|
|
if (!at_edit_point.empty()) {
|
|
|
|
have_edit_point = true;
|
|
|
|
}
|
|
|
|
if (rs.empty()) {
|
|
|
|
rs.insert (rs.end(), at_edit_point.begin(), at_edit_point.end());
|
2017-02-15 13:00:28 -05:00
|
|
|
}
|
2017-02-14 10:09:32 -05:00
|
|
|
}
|
|
|
|
}
|
2017-02-10 16:12:28 -05:00
|
|
|
|
2017-02-16 04:29:04 -05:00
|
|
|
//std::cerr << "\tfinal have selection: " << have_selection
|
|
|
|
// << " have entered " << have_entered
|
|
|
|
// << " have edit point " << have_edit_point
|
|
|
|
// << " EP = " << enum_2_string (_edit_point)
|
|
|
|
// << std::endl;
|
|
|
|
|
2017-02-14 10:09:32 -05:00
|
|
|
typedef std::map<std::string,RegionAction> RegionActionMap;
|
2008-02-19 17:10:27 -05:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
_ignore_region_action = true;
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2017-02-14 10:09:32 -05:00
|
|
|
for (RegionActionMap::iterator x = region_action_map.begin(); x != region_action_map.end(); ++x) {
|
|
|
|
RegionActionTarget tgt = x->second.target;
|
|
|
|
bool sensitive = false;
|
|
|
|
|
|
|
|
if ((tgt & SelectedRegions) && have_selection) {
|
|
|
|
sensitive = true;
|
|
|
|
} else if ((tgt & EnteredRegions) && have_entered) {
|
|
|
|
sensitive = true;
|
|
|
|
} else if ((tgt & EditPointRegions) && have_edit_point) {
|
|
|
|
sensitive = true;
|
2019-07-30 14:02:15 -04:00
|
|
|
} else if ((tgt & ListSelection) && have_selected_source ) {
|
|
|
|
sensitive = true;
|
2017-02-14 10:09:32 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
x->second.action->set_sensitive (sensitive);
|
|
|
|
}
|
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
/* Look through the regions that are selected and make notes about what we have got */
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
bool have_audio = false;
|
2011-12-01 21:07:13 -05:00
|
|
|
bool have_multichannel_audio = false;
|
2010-11-03 18:19:29 -04:00
|
|
|
bool have_midi = false;
|
|
|
|
bool have_locked = false;
|
|
|
|
bool have_unlocked = false;
|
2013-03-12 17:00:09 -04:00
|
|
|
bool have_video_locked = false;
|
|
|
|
bool have_video_unlocked = false;
|
2010-11-03 18:19:29 -04:00
|
|
|
bool have_position_lock_style_audio = false;
|
|
|
|
bool have_position_lock_style_music = false;
|
|
|
|
bool have_muted = false;
|
|
|
|
bool have_unmuted = false;
|
|
|
|
bool have_opaque = false;
|
|
|
|
bool have_non_opaque = false;
|
|
|
|
bool have_not_at_natural_position = false;
|
|
|
|
bool have_envelope_active = false;
|
|
|
|
bool have_envelope_inactive = false;
|
|
|
|
bool have_non_unity_scale_amplitude = false;
|
2011-05-22 12:11:00 -04:00
|
|
|
bool have_compound_regions = false;
|
2012-05-07 08:03:26 -04:00
|
|
|
bool have_inactive_fade_in = false;
|
|
|
|
bool have_inactive_fade_out = false;
|
|
|
|
bool have_active_fade_in = false;
|
|
|
|
bool have_active_fade_out = false;
|
2016-04-30 20:02:25 -04:00
|
|
|
bool have_transients = false;
|
2022-12-17 07:12:06 -05:00
|
|
|
bool have_inverted_polarity = false;
|
|
|
|
bool have_non_inverted_polarity = false;
|
2010-11-03 18:19:29 -04:00
|
|
|
|
|
|
|
for (list<RegionView*>::const_iterator i = rs.begin(); i != rs.end(); ++i) {
|
|
|
|
|
2023-02-16 18:33:28 -05:00
|
|
|
std::shared_ptr<Region> r = (*i)->region ();
|
|
|
|
std::shared_ptr<AudioRegion> ar = std::dynamic_pointer_cast<AudioRegion> (r);
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
if (ar) {
|
|
|
|
have_audio = true;
|
2011-12-01 21:07:13 -05:00
|
|
|
if (ar->n_channels() > 1) {
|
|
|
|
have_multichannel_audio = true;
|
|
|
|
}
|
2010-11-03 18:19:29 -04:00
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2023-02-16 18:33:28 -05:00
|
|
|
if (std::dynamic_pointer_cast<MidiRegion> (r)) {
|
2010-11-03 18:19:29 -04:00
|
|
|
have_midi = true;
|
|
|
|
}
|
|
|
|
|
2011-05-22 12:11:00 -04:00
|
|
|
if (r->is_compound()) {
|
|
|
|
have_compound_regions = true;
|
|
|
|
}
|
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
if (r->locked()) {
|
|
|
|
have_locked = true;
|
2008-02-19 17:10:27 -05:00
|
|
|
} else {
|
2010-11-03 18:19:29 -04:00
|
|
|
have_unlocked = true;
|
|
|
|
}
|
2013-04-11 13:49:29 -04:00
|
|
|
|
2013-03-12 17:00:09 -04:00
|
|
|
if (r->video_locked()) {
|
|
|
|
have_video_locked = true;
|
|
|
|
} else {
|
|
|
|
have_video_unlocked = true;
|
|
|
|
}
|
2010-11-03 18:19:29 -04:00
|
|
|
|
2020-10-19 14:37:54 -04:00
|
|
|
if (r->position_time_domain() == Temporal::BeatTime) {
|
2010-11-03 18:19:29 -04:00
|
|
|
have_position_lock_style_music = true;
|
|
|
|
} else {
|
|
|
|
have_position_lock_style_audio = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (r->muted()) {
|
|
|
|
have_muted = true;
|
|
|
|
} else {
|
|
|
|
have_unmuted = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (r->opaque()) {
|
|
|
|
have_opaque = true;
|
|
|
|
} else {
|
|
|
|
have_non_opaque = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!r->at_natural_position()) {
|
|
|
|
have_not_at_natural_position = true;
|
|
|
|
}
|
|
|
|
|
2016-04-30 20:02:25 -04:00
|
|
|
if (r->has_transients ()){
|
|
|
|
have_transients = true;
|
|
|
|
}
|
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
if (ar) {
|
|
|
|
if (ar->envelope_active()) {
|
|
|
|
have_envelope_active = true;
|
|
|
|
} else {
|
|
|
|
have_envelope_inactive = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ar->scale_amplitude() != 1) {
|
|
|
|
have_non_unity_scale_amplitude = true;
|
|
|
|
}
|
2012-05-07 08:03:26 -04:00
|
|
|
|
|
|
|
if (ar->fade_in_active ()) {
|
|
|
|
have_active_fade_in = true;
|
|
|
|
} else {
|
|
|
|
have_inactive_fade_in = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ar->fade_out_active ()) {
|
|
|
|
have_active_fade_out = true;
|
|
|
|
} else {
|
|
|
|
have_inactive_fade_out = true;
|
|
|
|
}
|
2022-12-17 07:12:06 -05:00
|
|
|
|
2022-12-17 13:13:26 -05:00
|
|
|
if (ar->scale_amplitude () < 0) {
|
|
|
|
have_inverted_polarity = true;
|
|
|
|
} else {
|
|
|
|
have_non_inverted_polarity = true;
|
|
|
|
}
|
2010-11-03 18:19:29 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-30 20:02:25 -04:00
|
|
|
_region_actions->get_action("split-region-at-transients")->set_sensitive (have_transients);
|
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
if (rs.size() > 1) {
|
|
|
|
_region_actions->get_action("show-region-list-editor")->set_sensitive (false);
|
|
|
|
_region_actions->get_action("show-region-properties")->set_sensitive (false);
|
|
|
|
_region_actions->get_action("rename-region")->set_sensitive (false);
|
2022-06-29 10:09:12 -04:00
|
|
|
/* XXX need to check whether there is than 1 per
|
|
|
|
playlist, because otherwise this makes no sense.
|
|
|
|
*/
|
|
|
|
_region_actions->get_action("combine-regions")->set_sensitive (true);
|
2010-11-03 18:19:29 -04:00
|
|
|
} else if (rs.size() == 1) {
|
|
|
|
_region_actions->get_action("add-range-markers-from-region")->set_sensitive (false);
|
|
|
|
_region_actions->get_action("close-region-gaps")->set_sensitive (false);
|
2011-05-16 16:16:57 -04:00
|
|
|
_region_actions->get_action("combine-regions")->set_sensitive (false);
|
2011-06-01 13:00:29 -04:00
|
|
|
}
|
2010-11-03 18:19:29 -04:00
|
|
|
|
2011-12-01 21:07:13 -05:00
|
|
|
if (!have_multichannel_audio) {
|
|
|
|
_region_actions->get_action("split-multichannel-region")->set_sensitive (false);
|
|
|
|
}
|
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
if (!have_midi) {
|
2012-03-14 08:05:53 -04:00
|
|
|
editor_menu_actions->get_action("RegionMenuMIDI")->set_sensitive (false);
|
2010-11-03 18:19:29 -04:00
|
|
|
_region_actions->get_action("show-region-list-editor")->set_sensitive (false);
|
|
|
|
_region_actions->get_action("quantize-region")->set_sensitive (false);
|
2014-12-06 23:42:11 -05:00
|
|
|
_region_actions->get_action("legatize-region")->set_sensitive (false);
|
|
|
|
_region_actions->get_action("remove-overlap")->set_sensitive (false);
|
2015-10-12 12:04:52 -04:00
|
|
|
_region_actions->get_action("transform-region")->set_sensitive (false);
|
2022-08-18 11:27:43 -04:00
|
|
|
_region_actions->get_action("fork-region")->set_sensitive (false);
|
gtk2_ardour: implement "Unlink from unselected" for MIDI regions
An attempt to satisfy #8848.
Add a new action, "fork-regions-from-unselected", which unlinks all
selected MIDI regions from any unselected regions, but maintains links
within the selection, and add the new action to the region MIDI context
menu as "Unlink from unselected". Rename the existing "fork-region" action
to "fork-selected-regions", and amend the existing "Unlink from other
copies" menu item to "Unlink all selected regions" to (try to) clarify the
difference.
Attach the <Tertiary>U default key-binding to the new action: I personally
think it's generally slightly more useful (otherwise I wouldn't have
implemented it), though I'm not that fussed.
In the case that there's only one MIDI region selected, or that none of
the selected regions are mutually linked, both actions will have exactly
the same result. Ideally, we'd only show a single menu item in this case,
but that would require (a) implementing a function to check whether the
selection contains any linked regions, and (b) making the region MIDI
context sub-menu dynamically generated, so that it can change based on the
result of that function, neither of which I've tried to do yet.
2022-01-02 17:22:45 -05:00
|
|
|
_region_actions->get_action("fork-regions-from-unselected")->set_sensitive (false);
|
2012-01-20 10:53:41 -05:00
|
|
|
_region_actions->get_action("insert-patch-change-context")->set_sensitive (false);
|
|
|
|
_region_actions->get_action("insert-patch-change")->set_sensitive (false);
|
2011-04-05 22:04:37 -04:00
|
|
|
_region_actions->get_action("transpose-region")->set_sensitive (false);
|
2012-01-20 10:53:41 -05:00
|
|
|
} else {
|
2012-03-14 12:58:11 -04:00
|
|
|
editor_menu_actions->get_action("RegionMenuMIDI")->set_sensitive (true);
|
2012-01-20 10:53:41 -05:00
|
|
|
/* others were already marked sensitive */
|
2010-11-03 18:19:29 -04:00
|
|
|
}
|
|
|
|
|
2017-02-10 16:12:28 -05:00
|
|
|
/* ok, moving along... */
|
|
|
|
|
2011-05-22 12:11:00 -04:00
|
|
|
if (have_compound_regions) {
|
|
|
|
_region_actions->get_action("uncombine-regions")->set_sensitive (true);
|
2011-05-26 08:24:04 -04:00
|
|
|
} else {
|
|
|
|
_region_actions->get_action("uncombine-regions")->set_sensitive (false);
|
2011-05-22 12:11:00 -04:00
|
|
|
}
|
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
if (have_audio) {
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2022-12-17 13:13:26 -05:00
|
|
|
if (have_envelope_active != have_envelope_inactive) {
|
|
|
|
Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-active"))->set_active (have_envelope_active);
|
2010-11-03 18:19:29 -04:00
|
|
|
} else if (have_envelope_active && have_envelope_inactive) {
|
2022-12-17 13:13:26 -05:00
|
|
|
// Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-active"))->set_inconsistent (); // N/A
|
|
|
|
Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-active"))->set_sensitive (false);
|
2010-11-03 18:19:29 -04:00
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2022-12-17 13:13:26 -05:00
|
|
|
if (have_inverted_polarity != have_non_inverted_polarity) {
|
|
|
|
Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-polarity"))->set_active (have_inverted_polarity);
|
|
|
|
} else if (have_inverted_polarity && have_non_inverted_polarity) {
|
|
|
|
// Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-polarity"))->set_inconsistent (); // N/A
|
|
|
|
Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-polarity"))->set_sensitive (false);
|
2022-12-17 07:12:06 -05:00
|
|
|
}
|
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
} else {
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2016-03-11 11:26:27 -05:00
|
|
|
_region_actions->get_action("loudness-analyze-region")->set_sensitive (false);
|
|
|
|
_region_actions->get_action("spectral-analyze-region")->set_sensitive (false);
|
2010-11-03 18:19:29 -04:00
|
|
|
_region_actions->get_action("reset-region-gain-envelopes")->set_sensitive (false);
|
|
|
|
_region_actions->get_action("toggle-region-gain-envelope-active")->set_sensitive (false);
|
2011-04-05 22:04:37 -04:00
|
|
|
_region_actions->get_action("pitch-shift-region")->set_sensitive (false);
|
2015-09-30 17:20:27 -04:00
|
|
|
_region_actions->get_action("strip-region-silence")->set_sensitive (false);
|
|
|
|
_region_actions->get_action("show-rhythm-ferret")->set_sensitive (false);
|
2022-12-17 07:12:06 -05:00
|
|
|
_region_actions->get_action("toggle-region-polarity")->set_sensitive (false);
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!have_non_unity_scale_amplitude || !have_audio) {
|
2022-05-04 00:43:22 -04:00
|
|
|
_region_actions->get_action("reset-region-gain")->set_sensitive (false);
|
2010-11-03 18:19:29 -04:00
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2012-05-07 08:03:26 -04:00
|
|
|
Glib::RefPtr<ToggleAction> a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock"));
|
|
|
|
a->set_active (have_locked && !have_unlocked);
|
2010-11-03 18:19:29 -04:00
|
|
|
if (have_locked && have_unlocked) {
|
2012-05-07 08:03:26 -04:00
|
|
|
// a->set_inconsistent ();
|
2008-02-19 17:10:27 -05:00
|
|
|
}
|
2010-11-03 18:19:29 -04:00
|
|
|
|
2013-03-12 17:00:09 -04:00
|
|
|
a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-video-lock"));
|
|
|
|
a->set_active (have_video_locked && !have_video_unlocked);
|
|
|
|
if (have_video_locked && have_video_unlocked) {
|
|
|
|
// a->set_inconsistent ();
|
|
|
|
}
|
|
|
|
|
2012-05-07 08:03:26 -04:00
|
|
|
a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock-style"));
|
|
|
|
a->set_active (have_position_lock_style_music && !have_position_lock_style_audio);
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2017-02-01 06:58:48 -05:00
|
|
|
vector<Widget*> proxies = a->get_proxies();
|
|
|
|
for (vector<Widget*>::iterator p = proxies.begin(); p != proxies.end(); ++p) {
|
2017-02-04 11:11:14 -05:00
|
|
|
Gtk::CheckMenuItem* cmi = dynamic_cast<Gtk::CheckMenuItem*> (*p);
|
2017-02-01 06:58:48 -05:00
|
|
|
if (cmi) {
|
|
|
|
cmi->set_inconsistent (have_position_lock_style_music && have_position_lock_style_audio);
|
2017-01-31 10:08:04 -05:00
|
|
|
}
|
2010-11-03 18:19:29 -04:00
|
|
|
}
|
|
|
|
|
2012-05-07 08:03:26 -04:00
|
|
|
a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-mute"));
|
|
|
|
a->set_active (have_muted && !have_unmuted);
|
2010-11-03 18:19:29 -04:00
|
|
|
if (have_muted && have_unmuted) {
|
2012-05-07 08:03:26 -04:00
|
|
|
// a->set_inconsistent ();
|
2010-11-03 18:19:29 -04:00
|
|
|
}
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2012-05-07 08:03:26 -04:00
|
|
|
a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-opaque-region"));
|
|
|
|
a->set_active (have_opaque && !have_non_opaque);
|
2010-11-03 18:19:29 -04:00
|
|
|
if (have_opaque && have_non_opaque) {
|
2012-05-07 08:03:26 -04:00
|
|
|
// a->set_inconsistent ();
|
2010-11-03 18:19:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!have_not_at_natural_position) {
|
|
|
|
_region_actions->get_action("naturalize-region")->set_sensitive (false);
|
|
|
|
}
|
|
|
|
|
2019-12-06 19:13:38 -05:00
|
|
|
/* Todo: insert-region-from-source-list */
|
2010-11-03 18:19:29 -04:00
|
|
|
/* XXX: should also check that there is a track of the appropriate type for the selected region */
|
2019-05-29 17:18:23 -04:00
|
|
|
#if 0
|
2010-11-03 18:19:29 -04:00
|
|
|
if (_edit_point == EditAtMouse || _regions->get_single_selection() == 0 || selection->tracks.empty()) {
|
2019-07-30 14:02:15 -04:00
|
|
|
_region_actions->get_action("insert-region-from-source-list")->set_sensitive (false);
|
2010-11-03 18:19:29 -04:00
|
|
|
} else {
|
2019-07-30 14:02:15 -04:00
|
|
|
_region_actions->get_action("insert-region-from-source-list")->set_sensitive (true);
|
2010-11-03 18:19:29 -04:00
|
|
|
}
|
2019-05-29 17:18:23 -04:00
|
|
|
#endif
|
2010-11-03 18:19:29 -04:00
|
|
|
|
2012-05-07 08:03:26 -04:00
|
|
|
a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-fade-in"));
|
|
|
|
a->set_active (have_active_fade_in && !have_inactive_fade_in);
|
|
|
|
if (have_active_fade_in && have_inactive_fade_in) {
|
|
|
|
// a->set_inconsistent ();
|
|
|
|
}
|
|
|
|
|
|
|
|
a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-fade-out"));
|
|
|
|
a->set_active (have_active_fade_out && !have_inactive_fade_out);
|
|
|
|
|
|
|
|
if (have_active_fade_out && have_inactive_fade_out) {
|
|
|
|
// a->set_inconsistent ();
|
|
|
|
}
|
2015-10-05 10:17:49 -04:00
|
|
|
|
2012-05-07 08:03:26 -04:00
|
|
|
bool const have_active_fade = have_active_fade_in || have_active_fade_out;
|
|
|
|
bool const have_inactive_fade = have_inactive_fade_in || have_inactive_fade_out;
|
|
|
|
|
|
|
|
a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-fades"));
|
|
|
|
a->set_active (have_active_fade && !have_inactive_fade);
|
|
|
|
|
|
|
|
if (have_active_fade && have_inactive_fade) {
|
|
|
|
// a->set_inconsistent ();
|
|
|
|
}
|
2015-10-05 10:17:49 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
_ignore_region_action = false;
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2010-11-03 18:19:29 -04:00
|
|
|
_all_region_actions_sensitized = false;
|
2008-03-17 16:54:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::region_selection_changed ()
|
|
|
|
{
|
2009-07-03 18:42:22 -04:00
|
|
|
_regions->block_change_connection (true);
|
2009-01-18 05:41:56 -05:00
|
|
|
editor_regions_selection_changed_connection.block(true);
|
2009-07-03 18:42:22 -04:00
|
|
|
|
2010-09-28 13:27:58 -04:00
|
|
|
if (_region_selection_change_updates_region_list) {
|
2010-09-18 19:31:39 -04:00
|
|
|
_regions->unselect_all ();
|
|
|
|
}
|
2010-01-25 15:34:09 -05:00
|
|
|
|
2008-03-17 16:54:03 -04:00
|
|
|
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
|
|
|
|
(*i)->set_selected_regionviews (selection->regions);
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2011-10-07 16:09:01 -04:00
|
|
|
if (_region_selection_change_updates_region_list) {
|
|
|
|
_regions->set_selected (selection->regions);
|
|
|
|
}
|
2010-01-17 18:11:22 -05:00
|
|
|
|
2009-07-03 18:42:22 -04:00
|
|
|
_regions->block_change_connection (false);
|
2009-01-18 05:41:56 -05:00
|
|
|
editor_regions_selection_changed_connection.block(false);
|
2010-11-03 18:19:29 -04:00
|
|
|
|
2017-02-15 13:50:51 -05:00
|
|
|
sensitize_the_right_region_actions (false);
|
2012-01-30 17:53:22 -05:00
|
|
|
|
2015-01-16 12:17:09 -05:00
|
|
|
/* propagate into backend */
|
2019-08-23 17:54:34 -04:00
|
|
|
assert (_session);
|
2015-01-16 12:17:09 -05:00
|
|
|
|
2019-08-23 17:54:34 -04:00
|
|
|
if (!selection->regions.empty()) {
|
2020-10-19 14:37:54 -04:00
|
|
|
_session->set_object_selection (selection->regions.start_time(), selection->regions.end_time());
|
2019-08-23 17:54:34 -04:00
|
|
|
} else {
|
|
|
|
_session->clear_object_selection ();
|
2015-01-16 12:17:09 -05:00
|
|
|
}
|
|
|
|
|
2018-10-04 15:55:44 -04:00
|
|
|
if (_session->solo_selection_active()) {
|
2018-02-11 10:39:45 -05:00
|
|
|
play_solo_selection(false);
|
2018-10-04 15:55:44 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* set nudge button color */
|
|
|
|
if (! get_regions_from_selection_and_entered().empty()) {
|
|
|
|
/* nudge regions */
|
|
|
|
nudge_forward_button.set_name ("nudge button");
|
|
|
|
nudge_backward_button.set_name ("nudge button");
|
|
|
|
} else {
|
|
|
|
/* nudge marker or playhead */
|
2020-01-12 18:22:39 -05:00
|
|
|
nudge_forward_button.set_name ("transport button");
|
|
|
|
nudge_backward_button.set_name ("transport button");
|
2018-10-04 15:55:44 -04:00
|
|
|
}
|
2019-02-07 14:29:59 -05:00
|
|
|
|
|
|
|
//there are a few global Editor->Select actions which select regions even if you aren't in Object mode.
|
|
|
|
//if regions are selected, we must always force the mouse mode to Object...
|
|
|
|
//... otherwise the user is confusingly left with selected regions that can't be manipulated.
|
2020-04-16 14:16:45 -04:00
|
|
|
if (!selection->regions.empty() && !internal_editing()) {
|
2020-05-12 15:08:38 -04:00
|
|
|
|
|
|
|
/* if in MouseAudition and there's just 1 region selected
|
|
|
|
* (i.e. we just clicked on it), leave things as they are
|
2022-05-31 15:21:11 -04:00
|
|
|
*
|
|
|
|
* Ditto for TimeFX mode
|
2020-05-12 15:08:38 -04:00
|
|
|
*/
|
|
|
|
|
2022-05-31 15:21:11 -04:00
|
|
|
if (selection->regions.size() > 1 || (mouse_mode != Editing::MouseAudition && mouse_mode != Editing::MouseTimeFX)) {
|
2020-05-12 15:08:38 -04:00
|
|
|
set_mouse_mode (MouseObject, false);
|
|
|
|
}
|
2019-02-07 14:29:59 -05:00
|
|
|
}
|
2023-05-16 17:46:12 -04:00
|
|
|
update_selection_markers ();
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::point_selection_changed ()
|
|
|
|
{
|
|
|
|
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
|
|
|
|
(*i)->set_selected_points (selection->points);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-01-12 18:45:50 -05:00
|
|
|
Editor::select_all_in_track (Selection::Operation op)
|
2007-01-28 12:44:13 -05:00
|
|
|
{
|
|
|
|
list<Selectable *> touched;
|
|
|
|
|
2008-01-12 18:45:50 -05:00
|
|
|
if (!clicked_routeview) {
|
|
|
|
return;
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2015-03-25 08:31:23 -04:00
|
|
|
begin_reversible_selection_op (X_("Select All in Track"));
|
2014-12-22 08:30:23 -05:00
|
|
|
|
2020-10-19 14:37:54 -04:00
|
|
|
clicked_routeview->get_selectables (timepos_t(), timepos_t::max (Temporal::AudioTime), 0, DBL_MAX, touched);
|
2007-01-28 12:44:13 -05:00
|
|
|
|
|
|
|
switch (op) {
|
|
|
|
case Selection::Toggle:
|
|
|
|
selection->add (touched);
|
|
|
|
break;
|
|
|
|
case Selection::Set:
|
|
|
|
selection->set (touched);
|
|
|
|
break;
|
|
|
|
case Selection::Extend:
|
|
|
|
/* meaningless, because we're selecting everything */
|
|
|
|
break;
|
|
|
|
case Selection::Add:
|
|
|
|
selection->add (touched);
|
|
|
|
break;
|
|
|
|
}
|
2014-12-22 08:30:23 -05:00
|
|
|
|
|
|
|
commit_reversible_selection_op ();
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
2014-12-29 21:04:23 -05:00
|
|
|
bool
|
2011-09-30 13:55:14 -04:00
|
|
|
Editor::select_all_internal_edit (Selection::Operation)
|
2011-01-26 20:31:03 -05:00
|
|
|
{
|
2014-12-29 21:04:23 -05:00
|
|
|
bool selected = false;
|
|
|
|
|
2021-03-18 15:17:02 -04:00
|
|
|
RegionSelection copy (selection->regions);
|
|
|
|
|
|
|
|
for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
|
2011-03-02 22:53:46 -05:00
|
|
|
MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
|
2011-10-07 16:09:01 -04:00
|
|
|
if (mrv) {
|
|
|
|
mrv->select_all_notes ();
|
2014-12-29 21:04:23 -05:00
|
|
|
selected = true;
|
2011-10-07 16:09:01 -04:00
|
|
|
}
|
2011-01-26 20:31:03 -05:00
|
|
|
}
|
2014-12-29 21:04:23 -05:00
|
|
|
|
|
|
|
MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(entered_regionview);
|
|
|
|
if (mrv) {
|
|
|
|
mrv->select_all_notes ();
|
|
|
|
selected = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return selected;
|
2011-01-26 20:31:03 -05:00
|
|
|
}
|
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
void
|
2014-07-06 14:53:56 -04:00
|
|
|
Editor::select_all_objects (Selection::Operation op)
|
2007-01-28 12:44:13 -05:00
|
|
|
{
|
|
|
|
list<Selectable *> touched;
|
2008-01-10 17:22:29 -05:00
|
|
|
|
2014-12-29 21:04:23 -05:00
|
|
|
if (internal_editing() && select_all_internal_edit(op)) {
|
|
|
|
return; // Selected notes
|
2011-10-07 16:09:01 -04:00
|
|
|
}
|
2011-01-26 20:31:03 -05:00
|
|
|
|
2017-05-05 07:31:49 -04:00
|
|
|
TrackViewList ts;
|
|
|
|
|
|
|
|
if (selection->tracks.empty()) {
|
|
|
|
ts = track_views;
|
|
|
|
} else {
|
|
|
|
ts = selection->tracks;
|
|
|
|
}
|
|
|
|
|
2012-11-15 12:20:38 -05:00
|
|
|
for (TrackViewList::iterator iter = ts.begin(); iter != ts.end(); ++iter) {
|
2007-01-28 12:44:13 -05:00
|
|
|
if ((*iter)->hidden()) {
|
|
|
|
continue;
|
|
|
|
}
|
2020-10-19 14:37:54 -04:00
|
|
|
(*iter)->get_selectables (timepos_t(), timepos_t::max (Temporal::AudioTime), 0, DBL_MAX, touched);
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
2012-11-15 12:20:38 -05:00
|
|
|
|
2015-03-25 08:31:23 -04:00
|
|
|
begin_reversible_selection_op (X_("select all"));
|
2007-01-28 12:44:13 -05:00
|
|
|
switch (op) {
|
|
|
|
case Selection::Add:
|
|
|
|
selection->add (touched);
|
|
|
|
break;
|
|
|
|
case Selection::Toggle:
|
2017-05-05 07:31:49 -04:00
|
|
|
selection->toggle (touched);
|
2007-01-28 12:44:13 -05:00
|
|
|
break;
|
|
|
|
case Selection::Set:
|
|
|
|
selection->set (touched);
|
|
|
|
break;
|
|
|
|
case Selection::Extend:
|
|
|
|
/* meaningless, because we're selecting everything */
|
|
|
|
break;
|
|
|
|
}
|
2014-12-22 08:30:23 -05:00
|
|
|
commit_reversible_selection_op ();
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
2011-10-07 16:27:12 -04:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
void
|
2008-01-12 18:45:50 -05:00
|
|
|
Editor::invert_selection_in_track ()
|
2007-01-28 12:44:13 -05:00
|
|
|
{
|
|
|
|
list<Selectable *> touched;
|
|
|
|
|
2008-01-12 18:45:50 -05:00
|
|
|
if (!clicked_routeview) {
|
|
|
|
return;
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2015-03-25 08:31:23 -04:00
|
|
|
begin_reversible_selection_op (X_("Invert Selection in Track"));
|
2008-01-12 18:45:50 -05:00
|
|
|
clicked_routeview->get_inverted_selectables (*selection, touched);
|
2007-01-28 12:44:13 -05:00
|
|
|
selection->set (touched);
|
2014-12-22 08:30:23 -05:00
|
|
|
commit_reversible_selection_op ();
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::invert_selection ()
|
|
|
|
{
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2014-12-08 23:00:00 -05:00
|
|
|
if (internal_editing()) {
|
2020-04-16 14:16:45 -04:00
|
|
|
MidiRegionSelection ms = selection->midi_regions();
|
|
|
|
for (MidiRegionSelection::iterator i = ms.begin(); i != ms.end(); ++i) {
|
2011-10-07 16:27:12 -04:00
|
|
|
MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
|
|
|
|
if (mrv) {
|
|
|
|
mrv->invert_selection ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-08-24 09:50:37 -04:00
|
|
|
if (!selection->tracks.empty()) {
|
|
|
|
|
|
|
|
TrackViewList inverted;
|
|
|
|
|
|
|
|
for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
|
|
|
|
if (!(*iter)->selected()) {
|
|
|
|
inverted.push_back (*iter);
|
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
2018-08-24 09:50:37 -04:00
|
|
|
begin_reversible_selection_op (X_("Invert Track Selection"));
|
|
|
|
selection->set (inverted);
|
|
|
|
commit_reversible_selection_op ();
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
list<Selectable *> touched;
|
|
|
|
|
|
|
|
for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
|
|
|
|
if ((*iter)->hidden()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
(*iter)->get_inverted_selectables (*selection, touched);
|
|
|
|
}
|
|
|
|
|
|
|
|
begin_reversible_selection_op (X_("Invert ObjectSelection"));
|
|
|
|
selection->set (touched);
|
|
|
|
commit_reversible_selection_op ();
|
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
2017-09-18 12:39:17 -04:00
|
|
|
/** @param start Start time in session samples.
|
|
|
|
* @param end End time in session samples.
|
2010-08-06 19:28:44 -04:00
|
|
|
* @param top Top (lower) y limit in trackview coordinates (ie 0 at the top of the track view)
|
|
|
|
* @param bottom Bottom (higher) y limit in trackview coordinates (ie 0 at the top of the track view)
|
2010-08-10 06:38:48 -04:00
|
|
|
* @param preserve_if_selected true to leave the current selection alone if we're adding to the selection and all of the selectables
|
|
|
|
* within the region are already selected.
|
2010-01-03 07:04:29 -05:00
|
|
|
*/
|
2011-01-23 18:13:46 -05:00
|
|
|
void
|
2020-10-19 14:37:54 -04:00
|
|
|
Editor::select_all_within (timepos_t const & start, timepos_t const & end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op, bool preserve_if_selected)
|
2007-01-28 12:44:13 -05:00
|
|
|
{
|
2010-01-04 21:22:58 -05:00
|
|
|
list<Selectable*> found;
|
2007-01-28 12:44:13 -05:00
|
|
|
|
2007-04-19 14:23:23 -04:00
|
|
|
for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
|
2011-06-01 13:00:29 -04:00
|
|
|
|
2007-01-28 12:44:13 -05:00
|
|
|
if ((*iter)->hidden()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2010-01-04 21:22:58 -05:00
|
|
|
(*iter)->get_selectables (start, end, top, bot, found);
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
2010-08-04 11:41:55 -04:00
|
|
|
|
2010-01-04 22:15:28 -05:00
|
|
|
if (found.empty()) {
|
2014-02-25 22:16:34 -05:00
|
|
|
selection->clear_objects();
|
|
|
|
selection->clear_time ();
|
2011-01-23 18:13:46 -05:00
|
|
|
return;
|
2007-04-12 19:20:37 -04:00
|
|
|
}
|
|
|
|
|
2010-08-10 06:38:48 -04:00
|
|
|
if (preserve_if_selected && op != Selection::Toggle) {
|
2010-08-09 21:52:49 -04:00
|
|
|
list<Selectable*>::iterator i = found.begin();
|
2016-06-05 19:49:51 -04:00
|
|
|
while (i != found.end() && (*i)->selected()) {
|
2010-08-09 21:52:49 -04:00
|
|
|
++i;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i == found.end()) {
|
2011-01-23 18:13:46 -05:00
|
|
|
return;
|
2010-08-09 21:52:49 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-25 08:31:23 -04:00
|
|
|
begin_reversible_selection_op (X_("select all within"));
|
2007-01-28 12:44:13 -05:00
|
|
|
switch (op) {
|
|
|
|
case Selection::Add:
|
2010-01-04 22:15:28 -05:00
|
|
|
selection->add (found);
|
2007-01-28 12:44:13 -05:00
|
|
|
break;
|
|
|
|
case Selection::Toggle:
|
2010-01-04 22:15:28 -05:00
|
|
|
selection->toggle (found);
|
2007-01-28 12:44:13 -05:00
|
|
|
break;
|
|
|
|
case Selection::Set:
|
2010-01-04 22:15:28 -05:00
|
|
|
selection->set (found);
|
2007-01-28 12:44:13 -05:00
|
|
|
break;
|
|
|
|
case Selection::Extend:
|
|
|
|
/* not defined yet */
|
|
|
|
break;
|
|
|
|
}
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2014-12-22 08:30:23 -05:00
|
|
|
commit_reversible_selection_op ();
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-01-12 18:45:50 -05:00
|
|
|
Editor::set_selection_from_region ()
|
2007-01-28 12:44:13 -05:00
|
|
|
{
|
|
|
|
if (selection->regions.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-04-24 14:17:09 -04:00
|
|
|
/* find all the tracks that have selected regions */
|
|
|
|
|
|
|
|
set<TimeAxisView*> tracks;
|
2015-10-05 10:17:49 -04:00
|
|
|
|
2015-04-24 14:17:09 -04:00
|
|
|
for (RegionSelection::const_iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
|
|
|
|
tracks.insert (&(*r)->get_time_axis_view());
|
|
|
|
}
|
|
|
|
|
|
|
|
TrackViewList tvl;
|
|
|
|
tvl.insert (tvl.end(), tracks.begin(), tracks.end());
|
|
|
|
|
2015-04-24 14:41:33 -04:00
|
|
|
/* select range (this will clear the region selection) */
|
|
|
|
|
2020-10-19 14:37:54 -04:00
|
|
|
selection->set (selection->regions.start_time(), selection->regions.end_time());
|
2015-04-24 14:41:33 -04:00
|
|
|
|
|
|
|
/* and select the tracks */
|
2015-10-05 10:17:49 -04:00
|
|
|
|
2015-04-24 14:17:09 -04:00
|
|
|
selection->set (tvl);
|
2015-10-05 10:17:49 -04:00
|
|
|
|
2018-02-15 17:06:19 -05:00
|
|
|
if (!get_smart_mode () || !(mouse_mode == Editing::MouseObject) ) {
|
2017-04-28 08:57:13 -04:00
|
|
|
set_mouse_mode (Editing::MouseRange, false);
|
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::set_selection_from_punch()
|
|
|
|
{
|
|
|
|
Location* location;
|
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
if ((location = _session->locations()->auto_punch_location()) == 0) {
|
2007-01-28 12:44:13 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
set_selection_from_range (*location);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::set_selection_from_loop()
|
|
|
|
{
|
|
|
|
Location* location;
|
|
|
|
|
2009-12-17 13:24:23 -05:00
|
|
|
if ((location = _session->locations()->auto_loop_location()) == 0) {
|
2007-01-28 12:44:13 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
set_selection_from_range (*location);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::set_selection_from_range (Location& loc)
|
|
|
|
{
|
2015-03-25 08:31:23 -04:00
|
|
|
begin_reversible_selection_op (X_("set selection from range"));
|
2017-12-11 11:03:15 -05:00
|
|
|
|
2009-12-13 16:27:19 -05:00
|
|
|
selection->set (loc.start(), loc.end());
|
2017-12-11 11:03:15 -05:00
|
|
|
|
|
|
|
// if no tracks are selected, enable all tracks
|
|
|
|
// (_something_ has to be selected for any range selection, otherwise the user won't see anything)
|
2017-12-11 18:13:12 -05:00
|
|
|
if (selection->tracks.empty()) {
|
2020-01-22 11:30:05 -05:00
|
|
|
select_all_visible_lanes();
|
2017-12-11 11:03:15 -05:00
|
|
|
}
|
|
|
|
|
2014-12-22 08:30:23 -05:00
|
|
|
commit_reversible_selection_op ();
|
2007-01-28 12:44:13 -05:00
|
|
|
|
2017-04-28 09:07:41 -04:00
|
|
|
if (!get_smart_mode () || mouse_mode != Editing::MouseObject) {
|
|
|
|
set_mouse_mode (MouseRange, false);
|
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::select_all_selectables_using_time_selection ()
|
|
|
|
{
|
|
|
|
list<Selectable *> touched;
|
|
|
|
|
|
|
|
if (selection->time.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-10-19 14:37:54 -04:00
|
|
|
timepos_t start = selection->time[clicked_selection].start();
|
|
|
|
timepos_t end = selection->time[clicked_selection].end();
|
2007-01-28 12:44:13 -05:00
|
|
|
|
2020-10-19 14:37:54 -04:00
|
|
|
const timecnt_t distance = start.distance (end);
|
|
|
|
|
2021-12-11 09:51:31 -05:00
|
|
|
if (distance.is_negative () || distance.is_zero ()) {
|
2007-01-28 12:44:13 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-12-13 14:09:52 -05:00
|
|
|
TrackViewList* ts;
|
2008-01-10 17:22:29 -05:00
|
|
|
|
|
|
|
if (selection->tracks.empty()) {
|
|
|
|
ts = &track_views;
|
|
|
|
} else {
|
|
|
|
ts = &selection->tracks;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
|
2007-01-28 12:44:13 -05:00
|
|
|
if ((*iter)->hidden()) {
|
|
|
|
continue;
|
|
|
|
}
|
2020-10-19 14:37:54 -04:00
|
|
|
(*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
2015-03-25 08:31:23 -04:00
|
|
|
begin_reversible_selection_op (X_("select all from range"));
|
2007-01-28 12:44:13 -05:00
|
|
|
selection->set (touched);
|
2014-12-22 08:30:23 -05:00
|
|
|
commit_reversible_selection_op ();
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::select_all_selectables_using_punch()
|
|
|
|
{
|
2009-12-17 13:24:23 -05:00
|
|
|
Location* location = _session->locations()->auto_punch_location();
|
2007-01-28 12:44:13 -05:00
|
|
|
list<Selectable *> touched;
|
|
|
|
|
2020-10-19 14:37:54 -04:00
|
|
|
if (location == 0 || (location->length_samples() <= 1)) {
|
2007-01-28 12:44:13 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-01-10 17:22:29 -05:00
|
|
|
|
2009-12-13 14:09:52 -05:00
|
|
|
TrackViewList* ts;
|
2008-01-10 17:22:29 -05:00
|
|
|
|
|
|
|
if (selection->tracks.empty()) {
|
|
|
|
ts = &track_views;
|
|
|
|
} else {
|
|
|
|
ts = &selection->tracks;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
|
2007-01-28 12:44:13 -05:00
|
|
|
if ((*iter)->hidden()) {
|
|
|
|
continue;
|
|
|
|
}
|
2020-10-19 14:37:54 -04:00
|
|
|
(*iter)->get_selectables (location->start(), location->end(), 0, DBL_MAX, touched);
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
2015-03-25 08:31:23 -04:00
|
|
|
begin_reversible_selection_op (X_("select all from punch"));
|
2007-01-28 12:44:13 -05:00
|
|
|
selection->set (touched);
|
2014-12-22 08:30:23 -05:00
|
|
|
commit_reversible_selection_op ();
|
2007-01-28 12:44:13 -05:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::select_all_selectables_using_loop()
|
|
|
|
{
|
2009-12-17 13:24:23 -05:00
|
|
|
Location* location = _session->locations()->auto_loop_location();
|
2007-01-28 12:44:13 -05:00
|
|
|
list<Selectable *> touched;
|
|
|
|
|
2020-10-19 14:37:54 -04:00
|
|
|
if (location == 0 || (location->length_samples() <= 1)) {
|
2007-01-28 12:44:13 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-01-10 17:22:29 -05:00
|
|
|
|
2009-12-13 14:09:52 -05:00
|
|
|
TrackViewList* ts;
|
2008-01-10 17:22:29 -05:00
|
|
|
|
|
|
|
if (selection->tracks.empty()) {
|
|
|
|
ts = &track_views;
|
|
|
|
} else {
|
|
|
|
ts = &selection->tracks;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
|
2007-01-28 12:44:13 -05:00
|
|
|
if ((*iter)->hidden()) {
|
|
|
|
continue;
|
|
|
|
}
|
2020-10-19 14:37:54 -04:00
|
|
|
(*iter)->get_selectables (location->start(), location->end(), 0, DBL_MAX, touched);
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
2015-03-25 08:31:23 -04:00
|
|
|
begin_reversible_selection_op (X_("select all from loop"));
|
2007-01-28 12:44:13 -05:00
|
|
|
selection->set (touched);
|
2014-12-22 08:30:23 -05:00
|
|
|
commit_reversible_selection_op ();
|
2007-01-28 12:44:13 -05:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-05-30 14:25:59 -04:00
|
|
|
Editor::select_all_selectables_using_cursor (EditorCursor *cursor, bool after)
|
2007-01-28 12:44:13 -05:00
|
|
|
{
|
2020-10-19 14:37:54 -04:00
|
|
|
timepos_t start;
|
|
|
|
timepos_t end;
|
2007-01-28 12:44:13 -05:00
|
|
|
list<Selectable *> touched;
|
|
|
|
|
|
|
|
if (after) {
|
2020-10-19 14:37:54 -04:00
|
|
|
start = timepos_t (cursor->current_sample());
|
|
|
|
end = timepos_t (_session->current_end_sample());
|
2007-01-28 12:44:13 -05:00
|
|
|
} else {
|
2017-09-18 12:39:17 -04:00
|
|
|
if (cursor->current_sample() > 0) {
|
2020-10-19 14:37:54 -04:00
|
|
|
start = timepos_t();
|
|
|
|
end = timepos_t (cursor->current_sample() - 1);
|
2007-01-28 12:44:13 -05:00
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-08 23:00:00 -05:00
|
|
|
if (internal_editing()) {
|
2011-10-07 17:11:19 -04:00
|
|
|
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
|
|
|
|
MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
|
|
|
|
if (mrv) {
|
|
|
|
mrv->select_range (start, end);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (after) {
|
2015-03-25 08:31:23 -04:00
|
|
|
begin_reversible_selection_op (X_("select all after cursor"));
|
2011-10-07 17:11:19 -04:00
|
|
|
} else {
|
2015-03-25 08:31:23 -04:00
|
|
|
begin_reversible_selection_op (X_("select all before cursor"));
|
2011-10-07 17:11:19 -04:00
|
|
|
}
|
2008-01-10 17:22:29 -05:00
|
|
|
|
2009-12-13 14:09:52 -05:00
|
|
|
TrackViewList* ts;
|
2008-01-10 17:22:29 -05:00
|
|
|
|
|
|
|
if (selection->tracks.empty()) {
|
|
|
|
ts = &track_views;
|
|
|
|
} else {
|
|
|
|
ts = &selection->tracks;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
|
2007-01-28 12:44:13 -05:00
|
|
|
if ((*iter)->hidden()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
(*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
|
|
|
|
}
|
|
|
|
selection->set (touched);
|
2014-12-22 08:30:23 -05:00
|
|
|
commit_reversible_selection_op ();
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-10-07 17:56:14 -04:00
|
|
|
Editor::select_all_selectables_using_edit (bool after, bool from_context_menu)
|
2007-01-28 12:44:13 -05:00
|
|
|
{
|
2020-10-19 14:37:54 -04:00
|
|
|
timepos_t start;
|
|
|
|
timepos_t end;
|
2007-01-28 12:44:13 -05:00
|
|
|
list<Selectable *> touched;
|
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
if (after) {
|
2015-10-07 17:56:14 -04:00
|
|
|
start = get_preferred_edit_position(EDIT_IGNORE_NONE, from_context_menu);
|
2020-10-19 14:37:54 -04:00
|
|
|
end = timepos_t (_session->current_end_sample());
|
2007-11-12 17:23:01 -05:00
|
|
|
} else {
|
2015-10-07 17:56:14 -04:00
|
|
|
if ((end = get_preferred_edit_position(EDIT_IGNORE_NONE, from_context_menu)) > 1) {
|
2020-10-19 14:37:54 -04:00
|
|
|
start = timepos_t ();
|
2022-10-07 19:30:45 -04:00
|
|
|
end = end.decrement();
|
2007-11-12 17:23:01 -05:00
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
}
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
2014-12-08 23:00:00 -05:00
|
|
|
if (internal_editing()) {
|
2011-10-07 17:11:19 -04:00
|
|
|
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
|
|
|
|
MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
|
|
|
|
mrv->select_range (start, end);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (after) {
|
2015-03-25 08:31:23 -04:00
|
|
|
begin_reversible_selection_op (X_("select all after edit"));
|
2011-10-07 17:11:19 -04:00
|
|
|
} else {
|
2015-03-25 08:31:23 -04:00
|
|
|
begin_reversible_selection_op (X_("select all before edit"));
|
2011-10-07 17:11:19 -04:00
|
|
|
}
|
2008-01-10 17:22:29 -05:00
|
|
|
|
2009-12-13 14:09:52 -05:00
|
|
|
TrackViewList* ts;
|
2008-01-10 17:22:29 -05:00
|
|
|
|
|
|
|
if (selection->tracks.empty()) {
|
|
|
|
ts = &track_views;
|
|
|
|
} else {
|
|
|
|
ts = &selection->tracks;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
|
2007-11-12 17:23:01 -05:00
|
|
|
if ((*iter)->hidden()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
(*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
|
|
|
|
}
|
|
|
|
selection->set (touched);
|
2014-12-22 08:30:23 -05:00
|
|
|
commit_reversible_selection_op ();
|
2007-11-12 17:23:01 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-01-09 13:20:02 -05:00
|
|
|
Editor::select_all_selectables_between (bool within)
|
2007-11-12 17:23:01 -05:00
|
|
|
{
|
2020-10-19 14:37:54 -04:00
|
|
|
timepos_t start;
|
|
|
|
timepos_t end;
|
2007-11-12 17:23:01 -05:00
|
|
|
list<Selectable *> touched;
|
|
|
|
|
|
|
|
if (!get_edit_op_range (start, end)) {
|
|
|
|
return;
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
2008-01-10 17:22:29 -05:00
|
|
|
|
2014-12-08 23:00:00 -05:00
|
|
|
if (internal_editing()) {
|
2011-10-07 17:11:19 -04:00
|
|
|
for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
|
|
|
|
MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
|
|
|
|
mrv->select_range (start, end);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-12-13 14:09:52 -05:00
|
|
|
TrackViewList* ts;
|
2008-01-10 17:22:29 -05:00
|
|
|
|
|
|
|
if (selection->tracks.empty()) {
|
|
|
|
ts = &track_views;
|
|
|
|
} else {
|
|
|
|
ts = &selection->tracks;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
|
2007-01-28 12:44:13 -05:00
|
|
|
if ((*iter)->hidden()) {
|
|
|
|
continue;
|
|
|
|
}
|
2015-01-09 13:20:02 -05:00
|
|
|
(*iter)->get_selectables (start, end, 0, DBL_MAX, touched, within);
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
2007-11-12 17:23:01 -05:00
|
|
|
|
2015-03-25 08:31:23 -04:00
|
|
|
begin_reversible_selection_op (X_("Select all Selectables Between"));
|
2007-01-28 12:44:13 -05:00
|
|
|
selection->set (touched);
|
2014-12-22 08:30:23 -05:00
|
|
|
commit_reversible_selection_op ();
|
2007-01-28 12:44:13 -05:00
|
|
|
}
|
|
|
|
|
2021-06-20 18:50:45 -04:00
|
|
|
void
|
2021-07-16 16:12:00 -04:00
|
|
|
Editor::get_regionviews_at_or_after (timepos_t const & pos, RegionSelection& regions)
|
2021-06-20 18:50:45 -04:00
|
|
|
{
|
|
|
|
for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
|
|
|
|
(*iter)->get_regionviews_at_or_after (pos, regions);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
void
|
|
|
|
Editor::select_range_between ()
|
|
|
|
{
|
2020-10-19 14:37:54 -04:00
|
|
|
timepos_t start;
|
|
|
|
timepos_t end;
|
2009-10-14 12:10:01 -04:00
|
|
|
|
2017-12-11 18:13:12 -05:00
|
|
|
if (!selection->time.empty()) {
|
2011-10-07 16:09:01 -04:00
|
|
|
selection->clear_time ();
|
|
|
|
}
|
2010-08-20 09:24:38 -04:00
|
|
|
|
2007-11-12 17:23:01 -05:00
|
|
|
if (!get_edit_op_range (start, end)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-04-28 09:07:41 -04:00
|
|
|
if (!get_smart_mode () || mouse_mode != Editing::MouseObject) {
|
|
|
|
set_mouse_mode (MouseRange, false);
|
|
|
|
}
|
|
|
|
|
2015-03-25 08:31:23 -04:00
|
|
|
begin_reversible_selection_op (X_("Select Range Between"));
|
2009-12-13 16:27:19 -05:00
|
|
|
selection->set (start, end);
|
2014-12-22 08:30:23 -05:00
|
|
|
commit_reversible_selection_op ();
|
2007-11-12 17:23:01 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2020-10-19 14:37:54 -04:00
|
|
|
Editor::get_edit_op_range (timepos_t& start, timepos_t& end) const
|
2007-11-12 17:23:01 -05:00
|
|
|
{
|
2012-11-28 12:07:35 -05:00
|
|
|
/* if an explicit range exists, use it */
|
2007-11-12 17:23:01 -05:00
|
|
|
|
2017-12-11 18:13:12 -05:00
|
|
|
if ((mouse_mode == MouseRange || get_smart_mode()) && !selection->time.empty()) {
|
2007-11-12 17:23:01 -05:00
|
|
|
/* we know that these are ordered */
|
2020-10-19 14:37:54 -04:00
|
|
|
start = selection->time.start_time();
|
|
|
|
end = selection->time.end_time();
|
2007-11-12 17:23:01 -05:00
|
|
|
return true;
|
|
|
|
} else {
|
2020-10-19 14:37:54 -04:00
|
|
|
start = timepos_t ();
|
|
|
|
end = timepos_t ();
|
2007-11-12 17:23:01 -05:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2008-01-10 16:20:59 -05:00
|
|
|
|
|
|
|
void
|
|
|
|
Editor::deselect_all ()
|
|
|
|
{
|
2015-03-25 08:31:23 -04:00
|
|
|
begin_reversible_selection_op (X_("Deselect All"));
|
2008-01-10 16:20:59 -05:00
|
|
|
selection->clear ();
|
2014-12-22 08:30:23 -05:00
|
|
|
commit_reversible_selection_op ();
|
2008-01-10 16:20:59 -05:00
|
|
|
}
|
2008-01-10 17:22:29 -05:00
|
|
|
|
2010-01-12 11:14:49 -05:00
|
|
|
long
|
2020-10-19 14:37:54 -04:00
|
|
|
Editor::select_range (timepos_t const & s, timepos_t const & e)
|
2010-01-01 17:11:15 -05:00
|
|
|
{
|
2015-03-25 08:31:23 -04:00
|
|
|
begin_reversible_selection_op (X_("Select Range"));
|
2012-01-30 17:53:22 -05:00
|
|
|
selection->add (clicked_axisview);
|
2010-01-01 17:11:15 -05:00
|
|
|
selection->time.clear ();
|
2014-12-22 08:30:23 -05:00
|
|
|
long ret = selection->set (s, e);
|
|
|
|
commit_reversible_selection_op ();
|
|
|
|
return ret;
|
2010-01-01 17:11:15 -05:00
|
|
|
}
|
2020-04-16 14:16:45 -04:00
|
|
|
|
|
|
|
void
|
|
|
|
Editor::catch_up_on_midi_selection ()
|
|
|
|
{
|
|
|
|
RegionSelection regions;
|
|
|
|
|
|
|
|
for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
|
|
|
|
if ((*iter)->hidden()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
MidiTimeAxisView* matv = dynamic_cast<MidiTimeAxisView*> (*iter);
|
|
|
|
if (!matv) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
matv->get_regions_with_selected_data (regions);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!regions.empty()) {
|
|
|
|
selection->set (regions);
|
|
|
|
}
|
|
|
|
}
|
2022-01-25 09:59:38 -05:00
|
|
|
|
|
|
|
struct ViewStripable {
|
|
|
|
TimeAxisView* tav;
|
2023-02-16 18:33:28 -05:00
|
|
|
std::shared_ptr<Stripable> stripable;
|
2022-01-25 09:59:38 -05:00
|
|
|
|
2023-02-16 18:33:28 -05:00
|
|
|
ViewStripable (TimeAxisView* t, std::shared_ptr<Stripable> s)
|
2022-01-25 09:59:38 -05:00
|
|
|
: tav (t), stripable (s) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
Editor::move_selected_tracks (bool up)
|
|
|
|
{
|
|
|
|
TimeAxisView* scroll_to = 0;
|
|
|
|
StripableList sl;
|
|
|
|
_session->get_stripables (sl);
|
|
|
|
|
|
|
|
if (sl.size() < 2) {
|
|
|
|
/* nope */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sl.sort (Stripable::Sorter());
|
|
|
|
|
|
|
|
std::list<ViewStripable> view_stripables;
|
|
|
|
|
|
|
|
/* build a list that includes time axis view information */
|
|
|
|
|
|
|
|
for (StripableList::const_iterator sli = sl.begin(); sli != sl.end(); ++sli) {
|
|
|
|
TimeAxisView* tv = time_axis_view_from_stripable (*sli);
|
|
|
|
view_stripables.push_back (ViewStripable (tv, *sli));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* for each selected stripable, move it above or below the adjacent
|
|
|
|
* stripable that has a time-axis view representation here. If there's
|
|
|
|
* no such representation, then
|
|
|
|
*/
|
|
|
|
|
|
|
|
list<ViewStripable>::iterator unselected_neighbour;
|
|
|
|
list<ViewStripable>::iterator vsi;
|
|
|
|
|
|
|
|
{
|
|
|
|
PresentationInfo::ChangeSuspender cs;
|
|
|
|
|
|
|
|
if (up) {
|
|
|
|
unselected_neighbour = view_stripables.end ();
|
|
|
|
vsi = view_stripables.begin();
|
|
|
|
|
|
|
|
while (vsi != view_stripables.end()) {
|
|
|
|
|
|
|
|
if (vsi->stripable->is_selected()) {
|
|
|
|
|
|
|
|
if (unselected_neighbour != view_stripables.end()) {
|
|
|
|
|
|
|
|
PresentationInfo::order_t unselected_neighbour_order = unselected_neighbour->stripable->presentation_info().order();
|
|
|
|
PresentationInfo::order_t my_order = vsi->stripable->presentation_info().order();
|
|
|
|
|
|
|
|
unselected_neighbour->stripable->set_presentation_order (my_order);
|
|
|
|
vsi->stripable->set_presentation_order (unselected_neighbour_order);
|
|
|
|
|
|
|
|
if (!scroll_to) {
|
|
|
|
scroll_to = vsi->tav;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
if (vsi->tav) {
|
|
|
|
unselected_neighbour = vsi;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
++vsi;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
unselected_neighbour = view_stripables.end();
|
|
|
|
vsi = unselected_neighbour;
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
|
|
|
--vsi;
|
|
|
|
|
|
|
|
if (vsi->stripable->is_selected()) {
|
|
|
|
|
|
|
|
if (unselected_neighbour != view_stripables.end()) {
|
|
|
|
|
|
|
|
PresentationInfo::order_t unselected_neighbour_order = unselected_neighbour->stripable->presentation_info().order();
|
|
|
|
PresentationInfo::order_t my_order = vsi->stripable->presentation_info().order();
|
|
|
|
|
|
|
|
unselected_neighbour->stripable->set_presentation_order (my_order);
|
|
|
|
vsi->stripable->set_presentation_order (unselected_neighbour_order);
|
|
|
|
|
|
|
|
if (!scroll_to) {
|
|
|
|
scroll_to = vsi->tav;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
if (vsi->tav) {
|
|
|
|
unselected_neighbour = vsi;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} while (vsi != view_stripables.begin());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (scroll_to) {
|
|
|
|
ensure_time_axis_view_is_visible (*scroll_to, false);
|
|
|
|
}
|
|
|
|
}
|