13
0
livetrax/gtk2_ardour/selection.cc
David Robillard e0aaed6d65 *** NEW CODING POLICY ***
All #include statements that include a header that is a part of a library
bundled with ardour MUST use quotes, not angle brackets.

Do this:

#include "ardour/types.h"

NOT this:

#include <ardour/types.h>

Rationale:

This is best practice in general, to ensure we include the local version
and not the system version.  That quotes mean "local" (in some sense)
and angle brackets mean "system" (in some sense) is a ubiquitous
convention and IIRC right in the C spec somewhere.

More pragmatically, this is required by (my) waf (stuff) for dependencies
to work correctly.  That is:

!!! FAILURE TO DO THIS CAN RESULT IN BROKEN BUILDS !!!

Failure to comply is punishable by death by torture. :)

P.S. It's not that dramatic in all cases, but this (in combination with some
GCC flags specific to the include type) is the best way I have found to be
absolutely 100% positive the local ones are being used (and we definitely
want to be absolutely 100% positive on that one).


git-svn-id: svn://localhost/ardour2/branches/3.0@4655 d708f5d6-7413-0410-9779-e7cbd77b26cf
2009-02-25 18:26:51 +00:00

838 lines
16 KiB
C++

/*
Copyright (C) 2002 Paul Davis
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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <algorithm>
#include <sigc++/bind.h>
#include "pbd/error.h"
#include "pbd/stacktrace.h"
#include "ardour/playlist.h"
#include "region_view.h"
#include "selection.h"
#include "selection_templates.h"
#include "time_axis_view.h"
#include "automation_time_axis.h"
#include "public_editor.h"
#include "i18n.h"
using namespace ARDOUR;
using namespace PBD;
using namespace sigc;
struct AudioRangeComparator {
bool operator()(AudioRange a, AudioRange b) {
return a.start < b.start;
}
};
Selection&
Selection::operator= (const Selection& other)
{
if (&other != this) {
regions = other.regions;
tracks = other.tracks;
time = other.time;
lines = other.lines;
}
return *this;
}
bool
operator== (const Selection& a, const Selection& b)
{
return a.regions == b.regions &&
a.tracks == b.tracks &&
a.time.track == b.time.track &&
a.time.group == b.time.group &&
a.time == b.time &&
a.lines == b.lines &&
a.playlists == b.playlists;
}
/** Clear everything from the Selection */
void
Selection::clear ()
{
clear_tracks ();
clear_regions ();
clear_points ();
clear_lines();
clear_time ();
clear_playlists ();
}
void
Selection::dump_region_layers()
{
cerr << "region selection layer dump" << endl;
for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
cerr << "layer: " << (int)(*i)->region()->layer() << endl;
}
}
void
Selection::clear_regions ()
{
if (!regions.empty()) {
regions.clear_all ();
RegionsChanged();
}
}
void
Selection::clear_tracks ()
{
if (!tracks.empty()) {
tracks.clear ();
TracksChanged();
}
}
void
Selection::clear_time ()
{
time.track = 0;
time.group = 0;
time.clear();
TimeChanged ();
}
void
Selection::clear_playlists ()
{
/* Selections own their playlists */
for (PlaylistSelection::iterator i = playlists.begin(); i != playlists.end(); ++i) {
/* selections own their own regions, which are copies of the "originals". make them go away */
(*i)->drop_regions ();
(*i)->release ();
}
if (!playlists.empty()) {
playlists.clear ();
PlaylistsChanged();
}
}
void
Selection::clear_lines ()
{
if (!lines.empty()) {
lines.clear ();
LinesChanged();
}
}
void
Selection::clear_markers ()
{
if (!markers.empty()) {
markers.clear ();
MarkersChanged();
}
}
void
Selection::toggle (boost::shared_ptr<Playlist> pl)
{
PlaylistSelection::iterator i;
if ((i = find (playlists.begin(), playlists.end(), pl)) == playlists.end()) {
pl->use ();
playlists.push_back(pl);
} else {
playlists.erase (i);
}
PlaylistsChanged ();
}
void
Selection::toggle (const list<TimeAxisView*>& track_list)
{
for (list<TimeAxisView*>::const_iterator i = track_list.begin(); i != track_list.end(); ++i) {
toggle ( (*i) );
}
}
void
Selection::toggle (TimeAxisView* track)
{
TrackSelection::iterator i;
if ((i = find (tracks.begin(), tracks.end(), track)) == tracks.end()) {
void (Selection::*pmf)(TimeAxisView*) = &Selection::remove;
track->GoingAway.connect (sigc::bind (mem_fun (*this, pmf), track));
tracks.push_back (track);
} else {
tracks.erase (i);
}
TracksChanged();
}
void
Selection::toggle (RegionView* r)
{
RegionSelection::iterator i;
if ((i = find (regions.begin(), regions.end(), r)) == regions.end()) {
add (r);
} else {
remove (*i);
}
RegionsChanged ();
}
void
Selection::toggle (vector<RegionView*>& r)
{
RegionSelection::iterator i;
for (vector<RegionView*>::iterator x = r.begin(); x != r.end(); ++x) {
if ((i = find (regions.begin(), regions.end(), (*x))) == regions.end()) {
add ((*x));
} else {
remove (*x);
}
}
RegionsChanged ();
}
long
Selection::toggle (nframes_t start, nframes_t end)
{
AudioRangeComparator cmp;
/* XXX this implementation is incorrect */
time.push_back (AudioRange (start, end, next_time_id++));
time.consolidate ();
time.sort (cmp);
TimeChanged ();
return next_time_id - 1;
}
void
Selection::add (boost::shared_ptr<Playlist> pl)
{
if (find (playlists.begin(), playlists.end(), pl) == playlists.end()) {
pl->use ();
playlists.push_back(pl);
PlaylistsChanged ();
}
}
void
Selection::add (const list<boost::shared_ptr<Playlist> >& pllist)
{
bool changed = false;
for (list<boost::shared_ptr<Playlist> >::const_iterator i = pllist.begin(); i != pllist.end(); ++i) {
if (find (playlists.begin(), playlists.end(), (*i)) == playlists.end()) {
(*i)->use ();
playlists.push_back (*i);
changed = true;
}
}
if (changed) {
PlaylistsChanged ();
}
}
void
Selection::add (const list<TimeAxisView*>& track_list)
{
bool changed = false;
for (list<TimeAxisView*>::const_iterator i = track_list.begin(); i != track_list.end(); ++i) {
if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
void (Selection::*pmf)(TimeAxisView*) = &Selection::remove;
(*i)->GoingAway.connect (sigc::bind (mem_fun (*this, pmf), (*i)));
tracks.push_back (*i);
changed = true;
}
}
if (changed) {
TracksChanged ();
}
}
void
Selection::add (TimeAxisView* track)
{
if (find (tracks.begin(), tracks.end(), track) == tracks.end()) {
void (Selection::*pmf)(TimeAxisView*) = &Selection::remove;
track->GoingAway.connect (sigc::bind (mem_fun (*this, pmf), track));
tracks.push_back (track);
TracksChanged();
}
}
void
Selection::add (vector<RegionView*>& v)
{
/* XXX This method or the add (const RegionSelection&) needs to go
*/
bool changed = false;
for (vector<RegionView*>::iterator i = v.begin(); i != v.end(); ++i) {
if (find (regions.begin(), regions.end(), (*i)) == regions.end()) {
changed = regions.add ((*i));
if (Config->get_link_region_and_track_selection() && changed) {
add (&(*i)->get_trackview());
}
}
}
if (changed) {
RegionsChanged ();
}
}
void
Selection::add (const RegionSelection& rs)
{
/* XXX This method or the add (const vector<RegionView*>&) needs to go
*/
bool changed = false;
for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
if (find (regions.begin(), regions.end(), (*i)) == regions.end()) {
changed = regions.add ((*i));
if (Config->get_link_region_and_track_selection() && changed) {
add (&(*i)->get_trackview());
}
}
}
if (changed) {
select_edit_group_regions ();
RegionsChanged ();
}
}
void
Selection::add (RegionView* r)
{
if (find (regions.begin(), regions.end(), r) == regions.end()) {
regions.add (r);
if (Config->get_link_region_and_track_selection()) {
add (&r->get_trackview());
}
RegionsChanged ();
}
}
long
Selection::add (nframes_t start, nframes_t end)
{
AudioRangeComparator cmp;
/* XXX this implementation is incorrect */
time.push_back (AudioRange (start, end, next_time_id++));
time.consolidate ();
time.sort (cmp);
TimeChanged ();
return next_time_id - 1;
}
void
Selection::replace (uint32_t sid, nframes_t start, nframes_t end)
{
for (list<AudioRange>::iterator i = time.begin(); i != time.end(); ++i) {
if ((*i).id == sid) {
time.erase (i);
time.push_back (AudioRange(start,end, sid));
/* don't consolidate here */
AudioRangeComparator cmp;
time.sort (cmp);
TimeChanged ();
break;
}
}
}
void
Selection::add (boost::shared_ptr<Evoral::ControlList> cl)
{
boost::shared_ptr<ARDOUR::AutomationList> al
= boost::dynamic_pointer_cast<ARDOUR::AutomationList>(cl);
if (!al) {
warning << "Programming error: Selected list is not an ARDOUR::AutomationList" << endmsg;
return;
return;
}
if (find (lines.begin(), lines.end(), al) == lines.end()) {
lines.push_back (al);
LinesChanged();
}
}
void
Selection::remove (TimeAxisView* track)
{
list<TimeAxisView*>::iterator i;
if ((i = find (tracks.begin(), tracks.end(), track)) != tracks.end()) {
tracks.erase (i);
TracksChanged();
}
}
void
Selection::remove (const list<TimeAxisView*>& track_list)
{
bool changed = false;
for (list<TimeAxisView*>::const_iterator i = track_list.begin(); i != track_list.end(); ++i) {
list<TimeAxisView*>::iterator x;
if ((x = find (tracks.begin(), tracks.end(), (*i))) != tracks.end()) {
tracks.erase (x);
changed = true;
}
}
if (changed) {
TracksChanged();
}
}
void
Selection::remove (boost::shared_ptr<Playlist> track)
{
list<boost::shared_ptr<Playlist> >::iterator i;
if ((i = find (playlists.begin(), playlists.end(), track)) != playlists.end()) {
playlists.erase (i);
PlaylistsChanged();
}
}
void
Selection::remove (const list<boost::shared_ptr<Playlist> >& pllist)
{
bool changed = false;
for (list<boost::shared_ptr<Playlist> >::const_iterator i = pllist.begin(); i != pllist.end(); ++i) {
list<boost::shared_ptr<Playlist> >::iterator x;
if ((x = find (playlists.begin(), playlists.end(), (*i))) != playlists.end()) {
playlists.erase (x);
changed = true;
}
}
if (changed) {
PlaylistsChanged();
}
}
void
Selection::remove (RegionView* r)
{
if (regions.remove (r)) {
RegionsChanged ();
}
if (Config->get_link_region_and_track_selection() && !regions.involves (r->get_trackview())) {
remove (&r->get_trackview());
}
}
void
Selection::remove (uint32_t selection_id)
{
if (time.empty()) {
return;
}
for (list<AudioRange>::iterator i = time.begin(); i != time.end(); ++i) {
if ((*i).id == selection_id) {
time.erase (i);
TimeChanged ();
break;
}
}
}
void
Selection::remove (nframes_t start, nframes_t end)
{
}
void
Selection::remove (boost::shared_ptr<ARDOUR::AutomationList> ac)
{
AutomationSelection::iterator i;
if ((i = find (lines.begin(), lines.end(), ac)) != lines.end()) {
lines.erase (i);
LinesChanged();
}
}
void
Selection::set (TimeAxisView* track)
{
clear_tracks ();
add (track);
}
void
Selection::set (const list<TimeAxisView*>& track_list)
{
clear_tracks ();
add (track_list);
}
void
Selection::set (boost::shared_ptr<Playlist> playlist)
{
clear_playlists ();
add (playlist);
}
void
Selection::set (const list<boost::shared_ptr<Playlist> >& pllist)
{
clear_playlists ();
add (pllist);
}
void
Selection::set (const RegionSelection& rs)
{
clear_regions();
regions = rs;
RegionsChanged(); /* EMIT SIGNAL */
}
void
Selection::set (RegionView* r, bool also_clear_tracks)
{
clear_regions ();
if (also_clear_tracks) {
clear_tracks ();
}
add (r);
}
void
Selection::set (vector<RegionView*>& v)
{
clear_regions ();
if (Config->get_link_region_and_track_selection()) {
clear_tracks ();
// make sure to deselect any automation selections
clear_points();
}
add (v);
}
long
Selection::set (TimeAxisView* track, nframes_t start, nframes_t end)
{
if ((start == 0 && end == 0) || end < start) {
return 0;
}
if (time.empty()) {
time.push_back (AudioRange (start, end, next_time_id++));
} else {
/* reuse the first entry, and remove all the rest */
while (time.size() > 1) {
time.pop_front();
}
time.front().start = start;
time.front().end = end;
}
if (track) {
time.track = track;
time.group = track->edit_group();
} else {
time.track = 0;
time.group = 0;
}
time.consolidate ();
TimeChanged ();
return time.front().id;
}
void
Selection::set (boost::shared_ptr<Evoral::ControlList> ac)
{
lines.clear();
add (ac);
}
bool
Selection::selected (Marker* m)
{
return find (markers.begin(), markers.end(), m) != markers.end();
}
bool
Selection::selected (TimeAxisView* tv)
{
return find (tracks.begin(), tracks.end(), tv) != tracks.end();
}
bool
Selection::selected (RegionView* rv)
{
return find (regions.begin(), regions.end(), rv) != regions.end();
}
bool
Selection::empty ()
{
return regions.empty () &&
tracks.empty () &&
points.empty () &&
playlists.empty () &&
lines.empty () &&
time.empty () &&
playlists.empty () &&
markers.empty()
;
}
void
Selection::toggle (const vector<AutomationSelectable*>& autos)
{
for (vector<AutomationSelectable*>::const_iterator x = autos.begin(); x != autos.end(); ++x) {
if ((*x)->get_selected()) {
points.remove (**x);
} else {
points.push_back (**x);
}
delete *x;
}
PointsChanged (); /* EMIT SIGNAL */
}
void
Selection::toggle (list<Selectable*>& selectables)
{
RegionView* rv;
AutomationSelectable* as;
vector<RegionView*> rvs;
vector<AutomationSelectable*> autos;
for (std::list<Selectable*>::iterator i = selectables.begin(); i != selectables.end(); ++i) {
if ((rv = dynamic_cast<RegionView*> (*i)) != 0) {
rvs.push_back (rv);
} else if ((as = dynamic_cast<AutomationSelectable*> (*i)) != 0) {
autos.push_back (as);
} else {
fatal << _("programming error: ")
<< X_("unknown selectable type passed to Selection::toggle()")
<< endmsg;
/*NOTREACHED*/
}
}
if (!rvs.empty()) {
toggle (rvs);
}
if (!autos.empty()) {
toggle (autos);
}
}
void
Selection::set (list<Selectable*>& selectables)
{
clear_regions();
clear_points ();
add (selectables);
}
void
Selection::add (list<Selectable*>& selectables)
{
RegionView* rv;
AutomationSelectable* as;
vector<RegionView*> rvs;
vector<AutomationSelectable*> autos;
for (std::list<Selectable*>::iterator i = selectables.begin(); i != selectables.end(); ++i) {
if ((rv = dynamic_cast<RegionView*> (*i)) != 0) {
rvs.push_back (rv);
} else if ((as = dynamic_cast<AutomationSelectable*> (*i)) != 0) {
autos.push_back (as);
} else {
fatal << _("programming error: ")
<< X_("unknown selectable type passed to Selection::add()")
<< endmsg;
/*NOTREACHED*/
}
}
if (!rvs.empty()) {
add (rvs);
}
if (!autos.empty()) {
add (autos);
}
}
void
Selection::clear_points ()
{
if (!points.empty()) {
points.clear ();
PointsChanged ();
}
}
void
Selection::add (vector<AutomationSelectable*>& autos)
{
for (vector<AutomationSelectable*>::iterator i = autos.begin(); i != autos.end(); ++i) {
points.push_back (**i);
}
PointsChanged ();
}
void
Selection::select_edit_group_regions ()
{
std::set<RegionView*> regions_to_add;
for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
vector<RegionView*> e;
editor->get_equivalent_regions (*i, e);
for (vector<RegionView*>::iterator j = e.begin(); j != e.end(); ++j) {
regions_to_add.insert(*j);
}
}
for (std::set<RegionView*>::iterator i = regions_to_add.begin(); i != regions_to_add.end(); ++i) {
add (*i);
}
}
void
Selection::set (Marker* m)
{
clear_markers ();
add (m);
}
void
Selection::toggle (Marker* m)
{
MarkerSelection::iterator i;
if ((i = find (markers.begin(), markers.end(), m)) == markers.end()) {
add (m);
} else {
remove (m);
}
}
void
Selection::remove (Marker* m)
{
MarkerSelection::iterator i;
if ((i = find (markers.begin(), markers.end(), m)) != markers.end()) {
markers.erase (i);
MarkersChanged();
}
}
void
Selection::add (Marker* m)
{
if (find (markers.begin(), markers.end(), m) == markers.end()) {
/* disambiguate which remove() for the compiler */
void (Selection::*pmf)(Marker*) = &Selection::remove;
m->GoingAway.connect (bind (mem_fun (*this, pmf), m));
markers.push_back (m);
MarkersChanged();
}
}
void
Selection::add (const list<Marker*>& m)
{
markers.insert (markers.end(), m.begin(), m.end());
MarkersChanged ();
}
void
MarkerSelection::range (nframes64_t& s, nframes64_t& e)
{
s = max_frames;
e = 0;
for (MarkerSelection::iterator i = begin(); i != end(); ++i) {
if ((*i)->position() < s) {
s = (*i)->position();
}
if ((*i)->position() > e) {
e = (*i)->position();
}
}
s = std::min (s, e);
e = std::max (s, e);
}