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) {
134 /* selections own their own regions, which are copies of the "originals". make them go away */
135 (*i)->drop_regions ();
139 if (!playlists.empty()) {
146 Selection::clear_lines ()
148 if (!lines.empty()) {
155 Selection::toggle (boost::shared_ptr<Redirect> r)
157 RedirectSelection::iterator i;
159 if ((i = find (redirects.begin(), redirects.end(), r)) == redirects.end()) {
160 redirects.push_back (r);
169 Selection::toggle (boost::shared_ptr<Playlist> pl)
171 PlaylistSelection::iterator i;
173 if ((i = find (playlists.begin(), playlists.end(), pl)) == playlists.end()) {
175 playlists.push_back(pl);
184 Selection::toggle (const list<TimeAxisView*>& track_list)
186 for (list<TimeAxisView*>::const_iterator i = track_list.begin(); i != track_list.end(); ++i) {
192 Selection::toggle (TimeAxisView* track)
194 TrackSelection::iterator i;
196 if ((i = find (tracks.begin(), tracks.end(), track)) == tracks.end()) {
197 void (Selection::*pmf)(TimeAxisView*) = &Selection::remove;
198 track->GoingAway.connect (sigc::bind (mem_fun (*this, pmf), track));
199 tracks.push_back (track);
208 Selection::toggle (RegionView* r)
210 RegionSelection::iterator i;
212 if ((i = find (regions.begin(), regions.end(), r)) == regions.end()) {
222 Selection::toggle (vector<RegionView*>& r)
224 RegionSelection::iterator i;
226 for (vector<RegionView*>::iterator x = r.begin(); x != r.end(); ++x) {
227 if ((i = find (regions.begin(), regions.end(), (*x))) == regions.end()) {
238 Selection::toggle (nframes_t start, nframes_t end)
240 AudioRangeComparator cmp;
242 /* XXX this implementation is incorrect */
244 time.push_back (AudioRange (start, end, next_time_id++));
250 return next_time_id - 1;
255 Selection::add (boost::shared_ptr<Redirect> r)
257 if (find (redirects.begin(), redirects.end(), r) == redirects.end()) {
258 redirects.push_back (r);
264 Selection::add (boost::shared_ptr<Playlist> pl)
266 if (find (playlists.begin(), playlists.end(), pl) == playlists.end()) {
268 playlists.push_back(pl);
274 Selection::add (const list<boost::shared_ptr<Playlist> >& pllist)
276 bool changed = false;
278 for (list<boost::shared_ptr<Playlist> >::const_iterator i = pllist.begin(); i != pllist.end(); ++i) {
279 if (find (playlists.begin(), playlists.end(), (*i)) == playlists.end()) {
281 playlists.push_back (*i);
292 Selection::add (const list<TimeAxisView*>& track_list)
294 bool changed = false;
296 for (list<TimeAxisView*>::const_iterator i = track_list.begin(); i != track_list.end(); ++i) {
297 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
298 void (Selection::*pmf)(TimeAxisView*) = &Selection::remove;
299 (*i)->GoingAway.connect (sigc::bind (mem_fun (*this, pmf), (*i)));
300 tracks.push_back (*i);
311 Selection::add (TimeAxisView* track)
313 if (find (tracks.begin(), tracks.end(), track) == tracks.end()) {
314 void (Selection::*pmf)(TimeAxisView*) = &Selection::remove;
315 track->GoingAway.connect (sigc::bind (mem_fun (*this, pmf), track));
316 tracks.push_back (track);
322 Selection::add (RegionView* r)
324 if (find (regions.begin(), regions.end(), r) == regions.end()) {
326 add (&r->get_trackview());
332 Selection::add (vector<RegionView*>& v)
334 bool changed = false;
336 for (vector<RegionView*>::iterator i = v.begin(); i != v.end(); ++i) {
337 if (find (regions.begin(), regions.end(), (*i)) == regions.end()) {
338 changed = regions.add ((*i));
340 add (&(*i)->get_trackview());
351 Selection::add (nframes_t start, nframes_t end)
353 AudioRangeComparator cmp;
355 /* XXX this implementation is incorrect */
357 time.push_back (AudioRange (start, end, next_time_id++));
363 return next_time_id - 1;
367 Selection::replace (uint32_t sid, nframes_t start, nframes_t end)
369 for (list<AudioRange>::iterator i = time.begin(); i != time.end(); ++i) {
370 if ((*i).id == sid) {
372 time.push_back (AudioRange(start,end, sid));
374 /* don't consolidate here */
377 AudioRangeComparator cmp;
387 Selection::add (AutomationList* ac)
389 if (find (lines.begin(), lines.end(), ac) == lines.end()) {
390 lines.push_back (ac);
396 Selection::remove (boost::shared_ptr<Redirect> r)
398 RedirectSelection::iterator i;
399 if ((i = find (redirects.begin(), redirects.end(), r)) != redirects.end()) {
406 Selection::remove (TimeAxisView* track)
408 list<TimeAxisView*>::iterator i;
409 if ((i = find (tracks.begin(), tracks.end(), track)) != tracks.end()) {
416 Selection::remove (const list<TimeAxisView*>& track_list)
418 bool changed = false;
420 for (list<TimeAxisView*>::const_iterator i = track_list.begin(); i != track_list.end(); ++i) {
422 list<TimeAxisView*>::iterator x;
424 if ((x = find (tracks.begin(), tracks.end(), (*i))) != tracks.end()) {
436 Selection::remove (boost::shared_ptr<Playlist> track)
438 list<boost::shared_ptr<Playlist> >::iterator i;
439 if ((i = find (playlists.begin(), playlists.end(), track)) != playlists.end()) {
446 Selection::remove (const list<boost::shared_ptr<Playlist> >& pllist)
448 bool changed = false;
450 for (list<boost::shared_ptr<Playlist> >::const_iterator i = pllist.begin(); i != pllist.end(); ++i) {
452 list<boost::shared_ptr<Playlist> >::iterator x;
454 if ((x = find (playlists.begin(), playlists.end(), (*i))) != playlists.end()) {
466 Selection::remove (RegionView* r)
468 if (regions.remove (r)) {
472 if (!regions.involves (r->get_trackview())) {
473 remove (&r->get_trackview());
479 Selection::remove (uint32_t selection_id)
485 for (list<AudioRange>::iterator i = time.begin(); i != time.end(); ++i) {
486 if ((*i).id == selection_id) {
496 Selection::remove (nframes_t start, nframes_t end)
501 Selection::remove (AutomationList *ac)
503 list<AutomationList*>::iterator i;
504 if ((i = find (lines.begin(), lines.end(), ac)) != lines.end()) {
511 Selection::set (boost::shared_ptr<Redirect> r)
518 Selection::set (TimeAxisView* track)
525 Selection::set (const list<TimeAxisView*>& track_list)
532 Selection::set (boost::shared_ptr<Playlist> playlist)
539 Selection::set (const list<boost::shared_ptr<Playlist> >& pllist)
546 Selection::set (RegionView* r)
554 Selection::set (vector<RegionView*>& v)
558 // make sure to deselect any automation selections
564 Selection::set (TimeAxisView* track, nframes_t start, nframes_t end)
566 if ((start == 0 && end == 0) || end < start) {
571 time.push_back (AudioRange (start, end, next_time_id++));
573 /* reuse the first entry, and remove all the rest */
575 while (time.size() > 1) {
578 time.front().start = start;
579 time.front().end = end;
584 time.group = track->edit_group();
594 return time.front().id;
598 Selection::set (AutomationList *ac)
605 Selection::selected (TimeAxisView* tv)
607 return find (tracks.begin(), tracks.end(), tv) != tracks.end();
611 Selection::selected (RegionView* rv)
613 return find (regions.begin(), regions.end(), rv) != regions.end();
619 return regions.empty () &&
622 playlists.empty () &&
625 playlists.empty () &&
631 Selection::toggle (const vector<AutomationSelectable*>& autos)
633 for (vector<AutomationSelectable*>::const_iterator x = autos.begin(); x != autos.end(); ++x) {
634 if ((*x)->get_selected()) {
637 points.push_back (**x);
643 PointsChanged (); /* EMIT SIGNAL */
647 Selection::toggle (list<Selectable*>& selectables)
650 AutomationSelectable* as;
651 vector<RegionView*> rvs;
652 vector<AutomationSelectable*> autos;
654 for (std::list<Selectable*>::iterator i = selectables.begin(); i != selectables.end(); ++i) {
655 if ((rv = dynamic_cast<RegionView*> (*i)) != 0) {
657 } else if ((as = dynamic_cast<AutomationSelectable*> (*i)) != 0) {
658 autos.push_back (as);
660 fatal << _("programming error: ")
661 << X_("unknown selectable type passed to Selection::toggle()")
671 if (!autos.empty()) {
677 Selection::set (list<Selectable*>& selectables)
686 Selection::add (list<Selectable*>& selectables)
689 AutomationSelectable* as;
690 vector<RegionView*> rvs;
691 vector<AutomationSelectable*> autos;
693 for (std::list<Selectable*>::iterator i = selectables.begin(); i != selectables.end(); ++i) {
694 if ((rv = dynamic_cast<RegionView*> (*i)) != 0) {
696 } else if ((as = dynamic_cast<AutomationSelectable*> (*i)) != 0) {
697 autos.push_back (as);
699 fatal << _("programming error: ")
700 << X_("unknown selectable type passed to Selection::add()")
710 if (!autos.empty()) {
716 Selection::clear_points ()
718 if (!points.empty()) {
725 Selection::add (vector<AutomationSelectable*>& autos)
727 for (vector<AutomationSelectable*>::iterator i = autos.begin(); i != autos.end(); ++i) {
728 points.push_back (**i);