Fix some unused parameter warnings.
[ardour.git] / gtk2_ardour / selection.cc
1 /*
2     Copyright (C) 2002 Paul Davis 
3
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.
8
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.
13
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.
17
18 */
19
20 #include <algorithm>
21 #include <sigc++/bind.h>
22 #include "pbd/error.h"
23 #include "pbd/stacktrace.h"
24
25 #include "ardour/playlist.h"
26 #include "ardour/rc_configuration.h"
27
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"
34
35 #include "i18n.h"
36
37 using namespace std;
38 using namespace ARDOUR;
39 using namespace PBD;
40 using namespace sigc;
41
42 struct AudioRangeComparator {
43     bool operator()(AudioRange a, AudioRange b) {
44             return a.start < b.start;
45     }
46 };
47
48 Selection&
49 Selection::operator= (const Selection& other)
50 {
51         if (&other != this) {
52                 regions = other.regions;
53                 tracks = other.tracks;
54                 time = other.time;
55                 lines = other.lines;
56         }
57         return *this;
58 }
59
60 bool
61 operator== (const Selection& a, const Selection& b)
62 {
63         return a.regions == b.regions &&
64                 a.tracks == b.tracks &&
65                 a.time.track == b.time.track &&
66                 a.time.group == b.time.group && 
67                 a.time == b.time &&
68                 a.lines == b.lines &&
69                 a.playlists == b.playlists;
70 }
71
72 /** Clear everything from the Selection */
73 void
74 Selection::clear ()
75 {
76         clear_tracks ();
77         clear_regions ();
78         clear_points ();
79         clear_lines();
80         clear_time ();
81         clear_playlists ();
82 }
83
84 void
85 Selection::dump_region_layers()
86 {
87         cerr << "region selection layer dump" << endl;
88         for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
89                 cerr << "layer: " << (int)(*i)->region()->layer() << endl;
90         }
91 }
92
93
94 void
95 Selection::clear_regions ()
96 {
97         if (!regions.empty()) {
98                 regions.clear_all ();
99                 RegionsChanged();
100         }
101 }
102
103 void
104 Selection::clear_tracks ()
105 {
106         if (!tracks.empty()) {
107                 tracks.clear ();
108                 TracksChanged();
109         }
110 }
111
112 void
113 Selection::clear_time ()
114 {
115         time.track = 0;
116         time.group = 0;
117         time.clear();
118
119         TimeChanged ();
120 }
121
122 void
123 Selection::clear_playlists ()
124 {
125         /* Selections own their playlists */
126
127         for (PlaylistSelection::iterator i = playlists.begin(); i != playlists.end(); ++i) {
128                 /* selections own their own regions, which are copies of the "originals". make them go away */
129                 (*i)->drop_regions ();
130                 (*i)->release ();
131         }
132
133         if (!playlists.empty()) {
134                 playlists.clear ();
135                 PlaylistsChanged();
136         }
137 }
138
139 void
140 Selection::clear_lines ()
141 {
142         if (!lines.empty()) {
143                 lines.clear ();
144                 LinesChanged();
145         }
146 }
147
148 void
149 Selection::clear_markers ()
150 {
151         if (!markers.empty()) {
152                 markers.clear ();
153                 MarkersChanged();
154         }
155 }
156
157 void
158 Selection::toggle (boost::shared_ptr<Playlist> pl)
159 {
160         PlaylistSelection::iterator i;
161
162         if ((i = find (playlists.begin(), playlists.end(), pl)) == playlists.end()) {
163                 pl->use ();
164                 playlists.push_back(pl);
165         } else {
166                 playlists.erase (i);
167         }
168
169         PlaylistsChanged ();
170 }
171
172 void
173 Selection::toggle (const list<TimeAxisView*>& track_list)
174 {
175         for (list<TimeAxisView*>::const_iterator i = track_list.begin(); i != track_list.end(); ++i) {
176                 toggle ( (*i) );
177         }
178 }
179
180 void
181 Selection::toggle (TimeAxisView* track)
182 {
183         TrackSelection::iterator i;
184         
185         if ((i = find (tracks.begin(), tracks.end(), track)) == tracks.end()) {
186                 void (Selection::*pmf)(TimeAxisView*) = &Selection::remove;
187                 track->GoingAway.connect (sigc::bind (mem_fun (*this, pmf), track));
188                 tracks.push_back (track);
189         } else {
190                 tracks.erase (i);
191         }
192
193         TracksChanged();
194 }
195
196 void
197 Selection::toggle (RegionView* r)
198 {
199         RegionSelection::iterator i;
200
201         if ((i = find (regions.begin(), regions.end(), r)) == regions.end()) {
202                 add (r);
203         } else {
204                 remove (*i);
205         }
206
207         RegionsChanged ();
208 }
209
210 void
211 Selection::toggle (vector<RegionView*>& r)
212 {
213         RegionSelection::iterator i;
214
215         for (vector<RegionView*>::iterator x = r.begin(); x != r.end(); ++x) {
216                 if ((i = find (regions.begin(), regions.end(), (*x))) == regions.end()) {
217                         add ((*x));
218                 } else {
219                         remove (*x);
220                 }
221         }
222
223         RegionsChanged ();
224 }
225
226 long
227 Selection::toggle (nframes_t start, nframes_t end)
228 {
229         AudioRangeComparator cmp;
230
231         /* XXX this implementation is incorrect */
232
233         time.push_back (AudioRange (start, end, next_time_id++));
234         time.consolidate ();
235         time.sort (cmp);
236         
237         TimeChanged ();
238
239         return next_time_id - 1;
240 }
241
242 void
243 Selection::add (boost::shared_ptr<Playlist> pl)
244 {
245         if (find (playlists.begin(), playlists.end(), pl) == playlists.end()) {
246                 pl->use ();
247                 playlists.push_back(pl);
248                 PlaylistsChanged ();
249         }
250 }
251
252 void
253 Selection::add (const list<boost::shared_ptr<Playlist> >& pllist)
254 {
255         bool changed = false;
256
257         for (list<boost::shared_ptr<Playlist> >::const_iterator i = pllist.begin(); i != pllist.end(); ++i) {
258                 if (find (playlists.begin(), playlists.end(), (*i)) == playlists.end()) {
259                         (*i)->use ();
260                         playlists.push_back (*i);
261                         changed = true;
262                 }
263         }
264         
265         if (changed) {
266                 PlaylistsChanged ();
267         }
268 }
269
270 void
271 Selection::add (const list<TimeAxisView*>& track_list)
272 {
273         list<TimeAxisView*> added = tracks.add (track_list);
274
275         for (list<TimeAxisView*>::const_iterator i = added.begin(); i != added.end(); ++i) {
276                 void (Selection::*pmf)(TimeAxisView*) = &Selection::remove;
277                 (*i)->GoingAway.connect (sigc::bind (mem_fun (*this, pmf), (*i)));
278         }
279         
280         if (!added.empty()) {
281                 TracksChanged ();
282         }
283 }
284
285 void
286 Selection::add (TimeAxisView* track)
287 {
288         if (find (tracks.begin(), tracks.end(), track) == tracks.end()) {
289                 void (Selection::*pmf)(TimeAxisView*) = &Selection::remove;
290                 track->GoingAway.connect (sigc::bind (mem_fun (*this, pmf), track));
291                 tracks.push_back (track);
292                 TracksChanged();
293         }
294 }
295
296 void
297 Selection::add (vector<RegionView*>& v)
298 {
299         /* XXX This method or the add (const RegionSelection&) needs to go
300          */
301
302         bool changed = false;
303         
304         for (vector<RegionView*>::iterator i = v.begin(); i != v.end(); ++i) {
305                 if (find (regions.begin(), regions.end(), (*i)) == regions.end()) {
306                         changed = regions.add ((*i));
307                         if (Config->get_link_region_and_track_selection() && changed) {
308                                 add (&(*i)->get_trackview());
309                         }
310                 }
311         }
312
313         if (changed) {
314                 RegionsChanged ();
315         }
316 }
317
318 void
319 Selection::add (const RegionSelection& rs)
320 {
321         /* XXX This method or the add (const vector<RegionView*>&) needs to go
322          */
323
324         bool changed = false;
325         
326         for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
327                 if (find (regions.begin(), regions.end(), (*i)) == regions.end()) {
328                         changed = regions.add ((*i));
329                         if (Config->get_link_region_and_track_selection() && changed) {
330                                 add (&(*i)->get_trackview());
331                         }
332                 }
333         }
334         
335         if (changed) {
336                 RegionsChanged ();
337         }
338 }
339
340 void
341 Selection::add (RegionView* r)
342 {
343         if (find (regions.begin(), regions.end(), r) == regions.end()) {
344                 regions.add (r);
345                 if (Config->get_link_region_and_track_selection()) {
346                         add (&r->get_trackview());
347                 }
348                 RegionsChanged ();
349         }
350 }
351
352 long
353 Selection::add (nframes_t start, nframes_t end)
354 {
355         AudioRangeComparator cmp;
356
357         /* XXX this implementation is incorrect */
358
359         time.push_back (AudioRange (start, end, next_time_id++));
360         time.consolidate ();
361         time.sort (cmp);
362         
363         TimeChanged ();
364
365         return next_time_id - 1;
366 }
367
368 void
369 Selection::replace (uint32_t sid, nframes_t start, nframes_t end)
370 {
371         for (list<AudioRange>::iterator i = time.begin(); i != time.end(); ++i) {
372                 if ((*i).id == sid) {
373                         time.erase (i);
374                         time.push_back (AudioRange(start,end, sid));
375
376                         /* don't consolidate here */
377
378
379                         AudioRangeComparator cmp;
380                         time.sort (cmp);
381
382                         TimeChanged ();
383                         break;
384                 }
385         }
386 }
387
388 void
389 Selection::add (boost::shared_ptr<Evoral::ControlList> cl)
390 {
391         boost::shared_ptr<ARDOUR::AutomationList> al
392                 = boost::dynamic_pointer_cast<ARDOUR::AutomationList>(cl);
393         if (!al) {
394                 warning << "Programming error: Selected list is not an ARDOUR::AutomationList" << endmsg;
395                 return;
396                 return;
397         }
398         if (find (lines.begin(), lines.end(), al) == lines.end()) {
399                 lines.push_back (al);
400                 LinesChanged();
401         }
402 }
403
404 void
405 Selection::remove (TimeAxisView* track)
406 {
407         list<TimeAxisView*>::iterator i;
408         if ((i = find (tracks.begin(), tracks.end(), track)) != tracks.end()) {
409                 tracks.erase (i);
410                 TracksChanged();
411         }
412 }
413
414 void
415 Selection::remove (const list<TimeAxisView*>& track_list)
416 {
417         bool changed = false;
418
419         for (list<TimeAxisView*>::const_iterator i = track_list.begin(); i != track_list.end(); ++i) {
420
421                 list<TimeAxisView*>::iterator x;
422
423                 if ((x = find (tracks.begin(), tracks.end(), (*i))) != tracks.end()) {
424                         tracks.erase (x);
425                         changed = true;
426                 }
427         }
428
429         if (changed) {
430                 TracksChanged();
431         }
432 }
433
434 void
435 Selection::remove (boost::shared_ptr<Playlist> track)
436 {
437         list<boost::shared_ptr<Playlist> >::iterator i;
438         if ((i = find (playlists.begin(), playlists.end(), track)) != playlists.end()) {
439                 playlists.erase (i);
440                 PlaylistsChanged();
441         }
442 }
443
444 void
445 Selection::remove (const list<boost::shared_ptr<Playlist> >& pllist)
446 {
447         bool changed = false;
448
449         for (list<boost::shared_ptr<Playlist> >::const_iterator i = pllist.begin(); i != pllist.end(); ++i) {
450
451                 list<boost::shared_ptr<Playlist> >::iterator x;
452
453                 if ((x = find (playlists.begin(), playlists.end(), (*i))) != playlists.end()) {
454                         playlists.erase (x);
455                         changed = true;
456                 }
457         }
458
459         if (changed) {
460                 PlaylistsChanged();
461         }
462 }
463
464 void
465 Selection::remove (RegionView* r)
466 {
467         if (regions.remove (r)) {
468                 RegionsChanged ();
469         }
470
471         if (Config->get_link_region_and_track_selection() && !regions.involves (r->get_trackview())) {
472                 remove (&r->get_trackview());
473         }
474 }
475
476
477 void
478 Selection::remove (uint32_t selection_id)
479 {
480         if (time.empty()) {
481                 return;
482         }
483
484         for (list<AudioRange>::iterator i = time.begin(); i != time.end(); ++i) {
485                 if ((*i).id == selection_id) {
486                         time.erase (i);
487                                                 
488                         TimeChanged ();
489                         break;
490                 }
491         }
492 }
493
494 void
495 Selection::remove (nframes_t /*start*/, nframes_t /*end*/)
496 {
497 }
498
499 void
500 Selection::remove (boost::shared_ptr<ARDOUR::AutomationList> ac)
501 {
502         AutomationSelection::iterator i;
503         if ((i = find (lines.begin(), lines.end(), ac)) != lines.end()) {
504                 lines.erase (i);
505                 LinesChanged();
506         }
507 }
508
509 void
510 Selection::set (TimeAxisView* track)
511 {
512         clear_tracks ();
513         add (track);
514 }
515
516 void
517 Selection::set (const list<TimeAxisView*>& track_list)
518 {
519         clear_tracks ();
520         add (track_list);
521 }
522
523 void
524 Selection::set (boost::shared_ptr<Playlist> playlist)
525 {
526         clear_playlists ();
527         add (playlist);
528 }
529
530 void
531 Selection::set (const list<boost::shared_ptr<Playlist> >& pllist)
532 {
533         clear_playlists ();
534         add (pllist);
535 }
536
537 void
538 Selection::set (const RegionSelection& rs)
539 {
540         clear_regions();
541         regions = rs;
542         RegionsChanged(); /* EMIT SIGNAL */
543 }
544
545 void
546 Selection::set (RegionView* r, bool also_clear_tracks)
547 {
548         clear_regions ();
549         if (also_clear_tracks) {
550                 clear_tracks ();
551         }
552         add (r);
553 }
554
555 void
556 Selection::set (vector<RegionView*>& v)
557 {
558         clear_regions ();
559         if (Config->get_link_region_and_track_selection()) {
560                 clear_tracks ();
561                 // make sure to deselect any automation selections
562                 clear_points();
563         }
564         add (v);
565 }
566
567 long
568 Selection::set (TimeAxisView* track, nframes_t start, nframes_t end)
569 {
570         if ((start == 0 && end == 0) || end < start) {
571                 return 0;
572         }
573
574         if (time.empty()) {
575                 time.push_back (AudioRange (start, end, next_time_id++));
576         } else {
577                 /* reuse the first entry, and remove all the rest */
578
579                 while (time.size() > 1) {
580                         time.pop_front();
581                 }
582                 time.front().start = start;
583                 time.front().end = end;
584         }
585
586         if (track) {
587                 time.track = track;
588                 time.group = track->route_group();
589         } else {
590                 time.track = 0;
591                 time.group = 0;
592         }
593
594         time.consolidate ();
595
596         TimeChanged ();
597
598         return time.front().id;
599 }
600
601 void
602 Selection::set (boost::shared_ptr<Evoral::ControlList> ac)
603 {
604         lines.clear();
605         add (ac);
606 }
607
608 bool
609 Selection::selected (Marker* m)
610 {
611         return find (markers.begin(), markers.end(), m) != markers.end();
612 }
613
614 bool
615 Selection::selected (TimeAxisView* tv)
616 {
617         return find (tracks.begin(), tracks.end(), tv) != tracks.end();
618 }
619
620 bool
621 Selection::selected (RegionView* rv)
622 {
623         return find (regions.begin(), regions.end(), rv) != regions.end();
624 }
625
626 bool
627 Selection::empty ()
628 {
629         return regions.empty () &&
630                 tracks.empty () &&
631                 points.empty () && 
632                 playlists.empty () && 
633                 lines.empty () &&
634                 time.empty () &&
635                 playlists.empty () &&
636                 markers.empty()
637                 ;
638 }
639
640 void
641 Selection::toggle (const vector<AutomationSelectable*>& autos)
642 {
643         for (vector<AutomationSelectable*>::const_iterator x = autos.begin(); x != autos.end(); ++x) {
644                 if ((*x)->get_selected()) {
645                         points.remove (**x);
646                 } else {
647                         points.push_back (**x);
648                 }
649
650                 delete *x;
651         }
652
653         PointsChanged (); /* EMIT SIGNAL */
654 }
655
656 void
657 Selection::toggle (list<Selectable*>& selectables)
658 {
659         RegionView* rv;
660         AutomationSelectable* as;
661         vector<RegionView*> rvs;
662         vector<AutomationSelectable*> autos;
663
664         for (std::list<Selectable*>::iterator i = selectables.begin(); i != selectables.end(); ++i) {
665                 if ((rv = dynamic_cast<RegionView*> (*i)) != 0) {
666                         rvs.push_back (rv);
667                 } else if ((as = dynamic_cast<AutomationSelectable*> (*i)) != 0) {
668                         autos.push_back (as);
669                 } else {
670                         fatal << _("programming error: ")
671                               << X_("unknown selectable type passed to Selection::toggle()")
672                               << endmsg;
673                         /*NOTREACHED*/
674                 }
675         }
676
677         if (!rvs.empty()) {
678                 toggle (rvs);
679         } 
680
681         if (!autos.empty()) {
682                 toggle (autos);
683         } 
684 }
685
686 void
687 Selection::set (list<Selectable*>& selectables)
688 {
689         clear_regions();
690         clear_points ();
691         add (selectables);
692 }
693
694
695 void
696 Selection::add (list<Selectable*>& selectables)
697 {
698         RegionView* rv;
699         AutomationSelectable* as;
700         vector<RegionView*> rvs;
701         vector<AutomationSelectable*> autos;
702
703         for (std::list<Selectable*>::iterator i = selectables.begin(); i != selectables.end(); ++i) {
704                 if ((rv = dynamic_cast<RegionView*> (*i)) != 0) {
705                         rvs.push_back (rv);
706                 } else if ((as = dynamic_cast<AutomationSelectable*> (*i)) != 0) {
707                         autos.push_back (as);
708                 } else {
709                         fatal << _("programming error: ")
710                               << X_("unknown selectable type passed to Selection::add()")
711                               << endmsg;
712                         /*NOTREACHED*/
713                 }
714         }
715
716         if (!rvs.empty()) {
717                 add (rvs);
718         } 
719
720         if (!autos.empty()) {
721                 add (autos);
722         } 
723 }
724
725 void
726 Selection::clear_points ()
727 {
728         if (!points.empty()) {
729                 points.clear ();
730                 PointsChanged ();
731         }
732 }
733
734 void
735 Selection::add (vector<AutomationSelectable*>& autos)
736 {
737         for (vector<AutomationSelectable*>::iterator i = autos.begin(); i != autos.end(); ++i) {
738                 points.push_back (**i);
739         }
740
741         PointsChanged ();
742 }
743
744 void
745 Selection::set (Marker* m)
746 {
747         clear_markers ();
748         add (m);
749 }
750
751 void
752 Selection::toggle (Marker* m)
753 {
754         MarkerSelection::iterator i;
755         
756         if ((i = find (markers.begin(), markers.end(), m)) == markers.end()) {
757                 add (m);
758         } else {
759                 remove (m);
760         }
761 }
762
763 void
764 Selection::remove (Marker* m)
765 {
766         MarkerSelection::iterator i;
767
768         if ((i = find (markers.begin(), markers.end(), m)) != markers.end()) {
769                 markers.erase (i);
770                 MarkersChanged();
771         }
772 }
773
774 void
775 Selection::add (Marker* m)
776 {
777         if (find (markers.begin(), markers.end(), m) == markers.end()) {
778
779                 /* disambiguate which remove() for the compiler */
780                 
781                 void (Selection::*pmf)(Marker*) = &Selection::remove;
782
783                 m->GoingAway.connect (bind (mem_fun (*this, pmf), m));
784
785                 markers.push_back (m);
786                 MarkersChanged();
787         }
788 }
789
790 void
791 Selection::add (const list<Marker*>& m)
792 {
793         markers.insert (markers.end(), m.begin(), m.end());
794         MarkersChanged ();
795 }
796
797 void
798 MarkerSelection::range (nframes64_t& s, nframes64_t& e)
799 {
800         s = max_frames;
801         e = 0;
802
803         for (MarkerSelection::iterator i = begin(); i != end(); ++i) {
804
805                 if ((*i)->position() < s) {
806                         s = (*i)->position();
807                 } 
808
809                 if ((*i)->position() > e) {
810                         e = (*i)->position();
811                 }
812         }
813
814         s = std::min (s, e);
815         e = std::max (s, e);
816 }