2 Copyright (C) 2002 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include <sigc++/bind.h>
22 #include <pbd/error.h>
24 #include <ardour/playlist.h>
26 #include "region_view.h"
27 #include "selection.h"
28 #include "selection_templates.h"
29 #include "time_axis_view.h"
30 #include "automation_time_axis.h"
34 using namespace ARDOUR;
38 struct AudioRangeComparator {
39 bool operator()(AudioRange a, AudioRange b) {
40 return a.start < b.start;
45 Selection::operator= (const Selection& other)
48 regions = other.regions;
49 tracks = other.tracks;
57 operator== (const Selection& a, const Selection& b)
59 return a.regions == b.regions &&
60 a.tracks == b.tracks &&
61 a.time.track == b.time.track &&
62 a.time.group == b.time.group &&
65 a.playlists == b.playlists &&
66 a.redirects == b.redirects;
82 Selection::dump_region_layers()
84 cerr << "region selection layer dump" << endl;
85 for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
86 cerr << "layer: " << (int)(*i)->region()->layer() << endl;
92 Selection::clear_redirects ()
94 if (!redirects.empty()) {
101 Selection::clear_regions ()
103 if (!regions.empty()) {
104 regions.clear_all ();
110 Selection::clear_tracks ()
112 if (!tracks.empty()) {
119 Selection::clear_time ()
129 Selection::clear_playlists ()
131 /* Selections own their playlists */
133 for (PlaylistSelection::iterator i = playlists.begin(); i != playlists.end(); ++i) {
137 if (!playlists.empty()) {
144 Selection::clear_lines ()
146 if (!lines.empty()) {
153 Selection::toggle (boost::shared_ptr<Redirect> r)
155 RedirectSelection::iterator i;
157 if ((i = find (redirects.begin(), redirects.end(), r)) == redirects.end()) {
158 redirects.push_back (r);
167 Selection::toggle (boost::shared_ptr<Playlist> pl)
169 PlaylistSelection::iterator i;
171 if ((i = find (playlists.begin(), playlists.end(), pl)) == playlists.end()) {
173 playlists.push_back(pl);
182 Selection::toggle (const list<TimeAxisView*>& track_list)
184 for (list<TimeAxisView*>::const_iterator i = track_list.begin(); i != track_list.end(); ++i) {
190 Selection::toggle (TimeAxisView* track)
192 TrackSelection::iterator i;
194 if ((i = find (tracks.begin(), tracks.end(), track)) == tracks.end()) {
195 void (Selection::*pmf)(TimeAxisView*) = &Selection::remove;
196 track->GoingAway.connect (sigc::bind (mem_fun (*this, pmf), track));
197 tracks.push_back (track);
206 Selection::toggle (RegionView* r)
208 RegionSelection::iterator i;
210 if ((i = find (regions.begin(), regions.end(), r)) == regions.end()) {
220 Selection::toggle (vector<RegionView*>& r)
222 RegionSelection::iterator i;
224 for (vector<RegionView*>::iterator x = r.begin(); x != r.end(); ++x) {
225 if ((i = find (regions.begin(), regions.end(), (*x))) == regions.end()) {
236 Selection::toggle (nframes_t start, nframes_t end)
238 AudioRangeComparator cmp;
240 /* XXX this implementation is incorrect */
242 time.push_back (AudioRange (start, end, next_time_id++));
248 return next_time_id - 1;
253 Selection::add (boost::shared_ptr<Redirect> r)
255 if (find (redirects.begin(), redirects.end(), r) == redirects.end()) {
256 redirects.push_back (r);
262 Selection::add (boost::shared_ptr<Playlist> pl)
264 if (find (playlists.begin(), playlists.end(), pl) == playlists.end()) {
266 playlists.push_back(pl);
272 Selection::add (const list<boost::shared_ptr<Playlist> >& pllist)
274 bool changed = false;
276 for (list<boost::shared_ptr<Playlist> >::const_iterator i = pllist.begin(); i != pllist.end(); ++i) {
277 if (find (playlists.begin(), playlists.end(), (*i)) == playlists.end()) {
279 playlists.push_back (*i);
290 Selection::add (const list<TimeAxisView*>& track_list)
292 bool changed = false;
294 for (list<TimeAxisView*>::const_iterator i = track_list.begin(); i != track_list.end(); ++i) {
295 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
296 void (Selection::*pmf)(TimeAxisView*) = &Selection::remove;
297 (*i)->GoingAway.connect (sigc::bind (mem_fun (*this, pmf), (*i)));
298 tracks.push_back (*i);
309 Selection::add (TimeAxisView* track)
311 if (find (tracks.begin(), tracks.end(), track) == tracks.end()) {
312 void (Selection::*pmf)(TimeAxisView*) = &Selection::remove;
313 track->GoingAway.connect (sigc::bind (mem_fun (*this, pmf), track));
314 tracks.push_back (track);
320 Selection::add (RegionView* r)
322 if (find (regions.begin(), regions.end(), r) == regions.end()) {
324 add (&r->get_trackview());
330 Selection::add (vector<RegionView*>& v)
332 bool changed = false;
334 for (vector<RegionView*>::iterator i = v.begin(); i != v.end(); ++i) {
335 if (find (regions.begin(), regions.end(), (*i)) == regions.end()) {
336 changed = regions.add ((*i));
338 add (&(*i)->get_trackview());
349 Selection::add (nframes_t start, nframes_t end)
351 AudioRangeComparator cmp;
353 /* XXX this implementation is incorrect */
355 time.push_back (AudioRange (start, end, next_time_id++));
361 return next_time_id - 1;
365 Selection::replace (uint32_t sid, nframes_t start, nframes_t end)
367 for (list<AudioRange>::iterator i = time.begin(); i != time.end(); ++i) {
368 if ((*i).id == sid) {
370 time.push_back (AudioRange(start,end, sid));
372 /* don't consolidate here */
375 AudioRangeComparator cmp;
385 Selection::add (AutomationList* ac)
387 if (find (lines.begin(), lines.end(), ac) == lines.end()) {
388 lines.push_back (ac);
394 Selection::remove (boost::shared_ptr<Redirect> r)
396 RedirectSelection::iterator i;
397 if ((i = find (redirects.begin(), redirects.end(), r)) != redirects.end()) {
404 Selection::remove (TimeAxisView* track)
406 list<TimeAxisView*>::iterator i;
407 if ((i = find (tracks.begin(), tracks.end(), track)) != tracks.end()) {
414 Selection::remove (const list<TimeAxisView*>& track_list)
416 bool changed = false;
418 for (list<TimeAxisView*>::const_iterator i = track_list.begin(); i != track_list.end(); ++i) {
420 list<TimeAxisView*>::iterator x;
422 if ((x = find (tracks.begin(), tracks.end(), (*i))) != tracks.end()) {
434 Selection::remove (boost::shared_ptr<Playlist> track)
436 list<boost::shared_ptr<Playlist> >::iterator i;
437 if ((i = find (playlists.begin(), playlists.end(), track)) != playlists.end()) {
444 Selection::remove (const list<boost::shared_ptr<Playlist> >& pllist)
446 bool changed = false;
448 for (list<boost::shared_ptr<Playlist> >::const_iterator i = pllist.begin(); i != pllist.end(); ++i) {
450 list<boost::shared_ptr<Playlist> >::iterator x;
452 if ((x = find (playlists.begin(), playlists.end(), (*i))) != playlists.end()) {
464 Selection::remove (RegionView* r)
466 if (regions.remove (r)) {
470 if (!regions.involves (r->get_trackview())) {
471 remove (&r->get_trackview());
477 Selection::remove (uint32_t selection_id)
483 for (list<AudioRange>::iterator i = time.begin(); i != time.end(); ++i) {
484 if ((*i).id == selection_id) {
494 Selection::remove (nframes_t start, nframes_t end)
499 Selection::remove (AutomationList *ac)
501 list<AutomationList*>::iterator i;
502 if ((i = find (lines.begin(), lines.end(), ac)) != lines.end()) {
509 Selection::set (boost::shared_ptr<Redirect> r)
516 Selection::set (TimeAxisView* track)
523 Selection::set (const list<TimeAxisView*>& track_list)
530 Selection::set (boost::shared_ptr<Playlist> playlist)
537 Selection::set (const list<boost::shared_ptr<Playlist> >& pllist)
544 Selection::set (RegionView* r)
552 Selection::set (vector<RegionView*>& v)
556 // make sure to deselect any automation selections
562 Selection::set (TimeAxisView* track, nframes_t start, nframes_t end)
564 if ((start == 0 && end == 0) || end < start) {
569 time.push_back (AudioRange (start, end, next_time_id++));
571 /* reuse the first entry, and remove all the rest */
573 while (time.size() > 1) {
576 time.front().start = start;
577 time.front().end = end;
582 time.group = track->edit_group();
592 return time.front().id;
596 Selection::set (AutomationList *ac)
603 Selection::selected (TimeAxisView* tv)
605 return find (tracks.begin(), tracks.end(), tv) != tracks.end();
609 Selection::selected (RegionView* rv)
611 return find (regions.begin(), regions.end(), rv) != regions.end();
617 return regions.empty () &&
620 playlists.empty () &&
623 playlists.empty () &&
629 Selection::toggle (const vector<AutomationSelectable*>& autos)
631 for (vector<AutomationSelectable*>::const_iterator x = autos.begin(); x != autos.end(); ++x) {
632 if ((*x)->get_selected()) {
635 points.push_back (**x);
641 PointsChanged (); /* EMIT SIGNAL */
645 Selection::toggle (list<Selectable*>& selectables)
648 AutomationSelectable* as;
649 vector<RegionView*> rvs;
650 vector<AutomationSelectable*> autos;
652 for (std::list<Selectable*>::iterator i = selectables.begin(); i != selectables.end(); ++i) {
653 if ((rv = dynamic_cast<RegionView*> (*i)) != 0) {
655 } else if ((as = dynamic_cast<AutomationSelectable*> (*i)) != 0) {
656 autos.push_back (as);
658 fatal << _("programming error: ")
659 << X_("unknown selectable type passed to Selection::toggle()")
669 if (!autos.empty()) {
675 Selection::set (list<Selectable*>& selectables)
684 Selection::add (list<Selectable*>& selectables)
687 AutomationSelectable* as;
688 vector<RegionView*> rvs;
689 vector<AutomationSelectable*> autos;
691 for (std::list<Selectable*>::iterator i = selectables.begin(); i != selectables.end(); ++i) {
692 if ((rv = dynamic_cast<RegionView*> (*i)) != 0) {
694 } else if ((as = dynamic_cast<AutomationSelectable*> (*i)) != 0) {
695 autos.push_back (as);
697 fatal << _("programming error: ")
698 << X_("unknown selectable type passed to Selection::add()")
708 if (!autos.empty()) {
714 Selection::clear_points ()
716 if (!points.empty()) {
723 Selection::add (vector<AutomationSelectable*>& autos)
725 for (vector<AutomationSelectable*>::iterator i = autos.begin(); i != autos.end(); ++i) {
726 points.push_back (**i);