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"
23 #include "pbd/stacktrace.h"
25 #include "ardour/playlist.h"
26 #include "ardour/rc_configuration.h"
28 #include "region_view.h"
29 #include "selection.h"
30 #include "selection_templates.h"
31 #include "time_axis_view.h"
32 #include "automation_time_axis.h"
33 #include "public_editor.h"
38 using namespace ARDOUR;
42 struct AudioRangeComparator {
43 bool operator()(AudioRange a, AudioRange b) {
44 return a.start < b.start;
49 Selection::operator= (const Selection& other)
52 regions = other.regions;
53 tracks = other.tracks;
62 operator== (const Selection& a, const Selection& b)
64 return a.regions == b.regions &&
65 a.tracks == b.tracks &&
66 a.time.track == b.time.track &&
67 a.time.group == b.time.group &&
70 a.playlists == b.playlists &&
74 /** Clear everything from the Selection */
88 Selection::dump_region_layers()
90 cerr << "region selection layer dump" << endl;
91 for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
92 cerr << "layer: " << (int)(*i)->region()->layer() << endl;
98 Selection::clear_regions ()
100 if (!regions.empty()) {
101 regions.clear_all ();
107 Selection::clear_tracks ()
109 if (!tracks.empty()) {
116 Selection::clear_midi ()
125 Selection::clear_time ()
135 Selection::clear_playlists ()
137 /* Selections own their playlists */
139 for (PlaylistSelection::iterator i = playlists.begin(); i != playlists.end(); ++i) {
140 /* selections own their own regions, which are copies of the "originals". make them go away */
141 (*i)->drop_regions ();
145 if (!playlists.empty()) {
152 Selection::clear_lines ()
154 if (!lines.empty()) {
161 Selection::clear_markers ()
163 if (!markers.empty()) {
170 Selection::toggle (boost::shared_ptr<Playlist> pl)
172 PlaylistSelection::iterator i;
174 if ((i = find (playlists.begin(), playlists.end(), pl)) == playlists.end()) {
176 playlists.push_back(pl);
185 Selection::toggle (const list<TimeAxisView*>& track_list)
187 for (list<TimeAxisView*>::const_iterator i = track_list.begin(); i != track_list.end(); ++i) {
193 Selection::toggle (TimeAxisView* track)
195 TrackSelection::iterator i;
197 if ((i = find (tracks.begin(), tracks.end(), track)) == tracks.end()) {
198 void (Selection::*pmf)(TimeAxisView*) = &Selection::remove;
199 track->GoingAway.connect (sigc::bind (mem_fun (*this, pmf), track));
200 tracks.push_back (track);
209 Selection::toggle (RegionView* r)
211 RegionSelection::iterator i;
213 if ((i = find (regions.begin(), regions.end(), r)) == regions.end()) {
223 Selection::toggle (MidiRegionView* mrv)
225 MidiSelection::iterator i;
227 if ((i = find (midi.begin(), midi.end(), mrv)) == midi.end()) {
237 Selection::toggle (vector<RegionView*>& r)
239 RegionSelection::iterator i;
241 for (vector<RegionView*>::iterator x = r.begin(); x != r.end(); ++x) {
242 if ((i = find (regions.begin(), regions.end(), (*x))) == regions.end()) {
253 Selection::toggle (nframes_t start, nframes_t end)
255 AudioRangeComparator cmp;
257 /* XXX this implementation is incorrect */
259 time.push_back (AudioRange (start, end, next_time_id++));
265 return next_time_id - 1;
269 Selection::add (boost::shared_ptr<Playlist> pl)
271 if (find (playlists.begin(), playlists.end(), pl) == playlists.end()) {
273 playlists.push_back(pl);
279 Selection::add (const list<boost::shared_ptr<Playlist> >& pllist)
281 bool changed = false;
283 for (list<boost::shared_ptr<Playlist> >::const_iterator i = pllist.begin(); i != pllist.end(); ++i) {
284 if (find (playlists.begin(), playlists.end(), (*i)) == playlists.end()) {
286 playlists.push_back (*i);
297 Selection::add (const list<TimeAxisView*>& track_list)
299 list<TimeAxisView*> added = tracks.add (track_list);
301 for (list<TimeAxisView*>::const_iterator i = added.begin(); i != added.end(); ++i) {
302 void (Selection::*pmf)(TimeAxisView*) = &Selection::remove;
303 (*i)->GoingAway.connect (sigc::bind (mem_fun (*this, pmf), (*i)));
306 if (!added.empty()) {
312 Selection::add (TimeAxisView* track)
314 if (find (tracks.begin(), tracks.end(), track) == tracks.end()) {
315 void (Selection::*pmf)(TimeAxisView*) = &Selection::remove;
316 track->GoingAway.connect (sigc::bind (mem_fun (*this, pmf), track));
317 tracks.push_back (track);
323 Selection::add (vector<RegionView*>& v)
325 /* XXX This method or the add (const RegionSelection&) needs to go
328 bool changed = false;
330 for (vector<RegionView*>::iterator i = v.begin(); i != v.end(); ++i) {
331 if (find (regions.begin(), regions.end(), (*i)) == regions.end()) {
332 changed = regions.add ((*i));
333 if (Config->get_link_region_and_track_selection() && changed) {
334 add (&(*i)->get_trackview());
345 Selection::add (const RegionSelection& rs)
347 /* XXX This method or the add (const vector<RegionView*>&) needs to go
350 bool changed = false;
352 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
353 if (find (regions.begin(), regions.end(), (*i)) == regions.end()) {
354 changed = regions.add ((*i));
355 if (Config->get_link_region_and_track_selection() && changed) {
356 add (&(*i)->get_trackview());
367 Selection::add (RegionView* r)
369 if (find (regions.begin(), regions.end(), r) == regions.end()) {
371 if (Config->get_link_region_and_track_selection()) {
372 add (&r->get_trackview());
379 Selection::add (MidiRegionView* mrv)
381 if (find (midi.begin(), midi.end(), mrv) == midi.end()) {
382 midi.push_back (mrv);
383 /* XXX should we do this? */
385 if (Config->get_link_region_and_track_selection()) {
386 add (&mrv->get_trackview());
394 Selection::add (nframes_t start, nframes_t end)
396 AudioRangeComparator cmp;
398 /* XXX this implementation is incorrect */
400 time.push_back (AudioRange (start, end, next_time_id++));
406 return next_time_id - 1;
410 Selection::replace (uint32_t sid, nframes_t start, nframes_t end)
412 for (list<AudioRange>::iterator i = time.begin(); i != time.end(); ++i) {
413 if ((*i).id == sid) {
415 time.push_back (AudioRange(start,end, sid));
417 /* don't consolidate here */
420 AudioRangeComparator cmp;
430 Selection::add (boost::shared_ptr<Evoral::ControlList> cl)
432 boost::shared_ptr<ARDOUR::AutomationList> al
433 = boost::dynamic_pointer_cast<ARDOUR::AutomationList>(cl);
435 warning << "Programming error: Selected list is not an ARDOUR::AutomationList" << endmsg;
439 if (find (lines.begin(), lines.end(), al) == lines.end()) {
440 lines.push_back (al);
446 Selection::remove (TimeAxisView* track)
448 list<TimeAxisView*>::iterator i;
449 if ((i = find (tracks.begin(), tracks.end(), track)) != tracks.end()) {
456 Selection::remove (const list<TimeAxisView*>& track_list)
458 bool changed = false;
460 for (list<TimeAxisView*>::const_iterator i = track_list.begin(); i != track_list.end(); ++i) {
462 list<TimeAxisView*>::iterator x;
464 if ((x = find (tracks.begin(), tracks.end(), (*i))) != tracks.end()) {
476 Selection::remove (boost::shared_ptr<Playlist> track)
478 list<boost::shared_ptr<Playlist> >::iterator i;
479 if ((i = find (playlists.begin(), playlists.end(), track)) != playlists.end()) {
486 Selection::remove (const list<boost::shared_ptr<Playlist> >& pllist)
488 bool changed = false;
490 for (list<boost::shared_ptr<Playlist> >::const_iterator i = pllist.begin(); i != pllist.end(); ++i) {
492 list<boost::shared_ptr<Playlist> >::iterator x;
494 if ((x = find (playlists.begin(), playlists.end(), (*i))) != playlists.end()) {
506 Selection::remove (RegionView* r)
508 if (regions.remove (r)) {
512 if (Config->get_link_region_and_track_selection() && !regions.involves (r->get_trackview())) {
513 remove (&r->get_trackview());
518 Selection::remove (MidiRegionView* mrv)
520 MidiSelection::iterator x;
522 if ((x = find (midi.begin(), midi.end(), mrv)) != midi.end()) {
528 /* XXX fix this up ? */
529 if (Config->get_link_region_and_track_selection() && !regions.involves (r->get_trackview())) {
530 remove (&r->get_trackview());
537 Selection::remove (uint32_t selection_id)
543 for (list<AudioRange>::iterator i = time.begin(); i != time.end(); ++i) {
544 if ((*i).id == selection_id) {
554 Selection::remove (nframes_t /*start*/, nframes_t /*end*/)
559 Selection::remove (boost::shared_ptr<ARDOUR::AutomationList> ac)
561 AutomationSelection::iterator i;
562 if ((i = find (lines.begin(), lines.end(), ac)) != lines.end()) {
569 Selection::set (TimeAxisView* track)
576 Selection::set (const list<TimeAxisView*>& track_list)
583 Selection::set (boost::shared_ptr<Playlist> playlist)
590 Selection::set (const list<boost::shared_ptr<Playlist> >& pllist)
597 Selection::set (const RegionSelection& rs)
601 RegionsChanged(); /* EMIT SIGNAL */
605 Selection::set (MidiRegionView* mrv)
612 Selection::set (RegionView* r, bool also_clear_tracks)
615 if (also_clear_tracks) {
622 Selection::set (vector<RegionView*>& v)
625 if (Config->get_link_region_and_track_selection()) {
627 // make sure to deselect any automation selections
634 Selection::set (TimeAxisView* track, nframes_t start, nframes_t end)
636 if ((start == 0 && end == 0) || end < start) {
641 time.push_back (AudioRange (start, end, next_time_id++));
643 /* reuse the first entry, and remove all the rest */
645 while (time.size() > 1) {
648 time.front().start = start;
649 time.front().end = end;
654 time.group = track->route_group();
664 return time.front().id;
668 Selection::set (boost::shared_ptr<Evoral::ControlList> ac)
675 Selection::selected (Marker* m)
677 return find (markers.begin(), markers.end(), m) != markers.end();
681 Selection::selected (TimeAxisView* tv)
683 return find (tracks.begin(), tracks.end(), tv) != tracks.end();
687 Selection::selected (RegionView* rv)
689 return find (regions.begin(), regions.end(), rv) != regions.end();
695 return regions.empty () &&
698 playlists.empty () &&
701 playlists.empty () &&
707 Selection::toggle (const vector<AutomationSelectable*>& autos)
709 for (vector<AutomationSelectable*>::const_iterator x = autos.begin(); x != autos.end(); ++x) {
710 if ((*x)->get_selected()) {
713 points.push_back (**x);
719 PointsChanged (); /* EMIT SIGNAL */
723 Selection::toggle (list<Selectable*>& selectables)
726 AutomationSelectable* as;
727 vector<RegionView*> rvs;
728 vector<AutomationSelectable*> autos;
730 for (std::list<Selectable*>::iterator i = selectables.begin(); i != selectables.end(); ++i) {
731 if ((rv = dynamic_cast<RegionView*> (*i)) != 0) {
733 } else if ((as = dynamic_cast<AutomationSelectable*> (*i)) != 0) {
734 autos.push_back (as);
736 fatal << _("programming error: ")
737 << X_("unknown selectable type passed to Selection::toggle()")
747 if (!autos.empty()) {
753 Selection::set (list<Selectable*>& selectables)
762 Selection::add (list<Selectable*>& selectables)
765 AutomationSelectable* as;
766 vector<RegionView*> rvs;
767 vector<AutomationSelectable*> autos;
769 for (std::list<Selectable*>::iterator i = selectables.begin(); i != selectables.end(); ++i) {
770 if ((rv = dynamic_cast<RegionView*> (*i)) != 0) {
772 } else if ((as = dynamic_cast<AutomationSelectable*> (*i)) != 0) {
773 autos.push_back (as);
775 fatal << _("programming error: ")
776 << X_("unknown selectable type passed to Selection::add()")
786 if (!autos.empty()) {
792 Selection::clear_points ()
794 if (!points.empty()) {
801 Selection::add (vector<AutomationSelectable*>& autos)
803 for (vector<AutomationSelectable*>::iterator i = autos.begin(); i != autos.end(); ++i) {
804 points.push_back (**i);
811 Selection::set (Marker* m)
818 Selection::toggle (Marker* m)
820 MarkerSelection::iterator i;
822 if ((i = find (markers.begin(), markers.end(), m)) == markers.end()) {
830 Selection::remove (Marker* m)
832 MarkerSelection::iterator i;
834 if ((i = find (markers.begin(), markers.end(), m)) != markers.end()) {
841 Selection::add (Marker* m)
843 if (find (markers.begin(), markers.end(), m) == markers.end()) {
845 /* disambiguate which remove() for the compiler */
847 void (Selection::*pmf)(Marker*) = &Selection::remove;
849 m->GoingAway.connect (bind (mem_fun (*this, pmf), m));
851 markers.push_back (m);
857 Selection::add (const list<Marker*>& m)
859 markers.insert (markers.end(), m.begin(), m.end());
864 MarkerSelection::range (nframes64_t& s, nframes64_t& e)
869 for (MarkerSelection::iterator i = begin(); i != end(); ++i) {
871 if ((*i)->position() < s) {
872 s = (*i)->position();
875 if ((*i)->position() > e) {
876 e = (*i)->position();