fe7d754d131dae14f4c4df4d5d20964204a67a76
[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     $Id$
19 */
20
21 #include <algorithm>
22 #include <sigc++/bind.h>
23 #include <pbd/error.h>
24
25 #include <ardour/playlist.h>
26
27 #include "regionview.h"
28 #include "selection.h"
29 #include "selection_templates.h"
30 #include "time_axis_view.h"
31 #include "automation_time_axis.h"
32
33 #include "i18n.h"
34
35 using namespace ARDOUR;
36 using namespace PBD;
37 using namespace sigc;
38
39 struct AudioRangeComparator {
40     bool operator()(AudioRange a, AudioRange b) {
41             return a.start < b.start;
42     }
43 };
44
45 Selection&
46 Selection::operator= (const Selection& other)
47 {
48         if (&other != this) {
49                 regions = other.regions;
50                 tracks = other.tracks;
51                 time = other.time;
52                 lines = other.lines;
53         }
54         return *this;
55 }
56
57 bool
58 operator== (const Selection& a, const Selection& b)
59 {
60         return a.regions == b.regions &&
61                 a.tracks == b.tracks &&
62                 a.time.track == b.time.track &&
63                 a.time.group == b.time.group && 
64                 a.time == b.time &&
65                 a.lines == b.lines &&
66                 a.playlists == b.playlists &&
67                 a.redirects == b.redirects;
68 }
69
70 void
71 Selection::clear ()
72 {
73         clear_tracks ();
74         clear_regions ();
75         clear_points ();
76         clear_lines();
77         clear_time ();
78         clear_playlists ();
79         clear_redirects ();
80 }
81
82 void
83 Selection::dump_region_layers()
84 {
85         cerr << "region selection layer dump" << endl;
86         for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
87                 cerr << "layer: " << (int)(*i)->region().layer() << endl;
88         }
89 }
90
91
92 void
93 Selection::clear_redirects ()
94 {
95         if (!redirects.empty()) {
96                 redirects.clear ();
97                 RedirectsChanged ();
98         }
99 }
100
101 void
102 Selection::clear_regions ()
103 {
104         if (!regions.empty()) {
105                 regions.clear_all ();
106                 RegionsChanged();
107         }
108 }
109
110 void
111 Selection::clear_tracks ()
112 {
113         if (!tracks.empty()) {
114                 tracks.clear ();
115                 TracksChanged();
116         }
117 }
118
119 void
120 Selection::clear_time ()
121 {
122         time.track = 0;
123         time.group = 0;
124         time.clear();
125
126         TimeChanged ();
127 }
128
129 void
130 Selection::clear_playlists ()
131 {
132         /* Selections own their playlists */
133
134         for (PlaylistSelection::iterator i = playlists.begin(); i != playlists.end(); ++i) {
135                 (*i)->unref ();
136         }
137
138         if (!playlists.empty()) {
139                 playlists.clear ();
140                 PlaylistsChanged();
141         }
142 }
143
144 void
145 Selection::clear_lines ()
146 {
147         if (!lines.empty()) {
148                 lines.clear ();
149                 LinesChanged();
150         }
151 }
152
153 void
154 Selection::toggle (Redirect* r)
155 {
156         RedirectSelection::iterator i;
157
158         if ((i = find (redirects.begin(), redirects.end(), r)) == redirects.end()) {
159                 redirects.push_back (r);
160         } else {
161                 redirects.erase (i);
162         }
163         RedirectsChanged();
164
165 }
166
167 void
168 Selection::toggle (Playlist* pl)
169 {
170         PlaylistSelection::iterator i;
171
172         if ((i = find (playlists.begin(), playlists.end(), pl)) == playlists.end()) {
173                 pl->ref ();
174                 playlists.push_back(pl);
175         } else {
176                 playlists.erase (i);
177         }
178
179         PlaylistsChanged ();
180 }
181
182 void
183 Selection::toggle (TimeAxisView* track)
184 {
185         TrackSelection::iterator i;
186         
187         if ((i = find (tracks.begin(), tracks.end(), track)) == tracks.end()) {
188                 void (Selection::*pmf)(TimeAxisView*) = &Selection::remove;
189                 track->GoingAway.connect (sigc::bind (mem_fun (*this, pmf), track));
190                 tracks.push_back (track);
191         } else {
192                 tracks.erase (i);
193         }
194
195         TracksChanged();
196 }
197
198 void
199 Selection::toggle (RegionView* r)
200 {
201         RegionSelection::iterator i;
202
203         if ((i = find (regions.begin(), regions.end(), r)) == regions.end()) {
204                 regions.add (r);
205         } else {
206                 regions.erase (i);
207         }
208
209         RegionsChanged ();
210 }
211
212 void
213 Selection::toggle (vector<RegionView*>& r)
214 {
215         RegionSelection::iterator i;
216
217         for (vector<RegionView*>::iterator x = r.begin(); x != r.end(); ++x) {
218                 if ((i = find (regions.begin(), regions.end(), (*x))) == regions.end()) {
219                         regions.add ((*x));
220                 } else {
221                         regions.erase (i);
222                 }
223         }
224
225         RegionsChanged ();
226 }
227
228 long
229 Selection::toggle (jack_nframes_t start, jack_nframes_t end)
230 {
231         AudioRangeComparator cmp;
232
233         /* XXX this implementation is incorrect */
234
235         time.push_back (AudioRange (start, end, next_time_id++));
236         time.consolidate ();
237         time.sort (cmp);
238         
239         TimeChanged ();
240
241         return next_time_id - 1;
242 }
243
244
245 void
246 Selection::add (Redirect* r)
247 {
248         if (find (redirects.begin(), redirects.end(), r) == redirects.end()) {
249                 redirects.push_back (r);
250                 RedirectsChanged();
251         }
252 }
253
254 void
255 Selection::add (Playlist* pl)
256 {
257         if (find (playlists.begin(), playlists.end(), pl) == playlists.end()) {
258                 pl->ref ();
259                 playlists.push_back(pl);
260                 PlaylistsChanged ();
261         }
262 }
263
264 void
265 Selection::add (const list<Playlist*>& pllist)
266 {
267         bool changed = false;
268
269         for (list<Playlist*>::const_iterator i = pllist.begin(); i != pllist.end(); ++i) {
270                 if (find (playlists.begin(), playlists.end(), (*i)) == playlists.end()) {
271                         (*i)->ref ();
272                         playlists.push_back (*i);
273                         changed = true;
274                 }
275         }
276         
277         if (changed) {
278                 PlaylistsChanged ();
279         }
280 }
281
282 void
283 Selection::add (const list<TimeAxisView*>& track_list)
284 {
285         bool changed = false;
286
287         for (list<TimeAxisView*>::const_iterator i = track_list.begin(); i != track_list.end(); ++i) {
288                 if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
289                         void (Selection::*pmf)(TimeAxisView*) = &Selection::remove;
290                         (*i)->GoingAway.connect (sigc::bind (mem_fun (*this, pmf), (*i)));
291                         tracks.push_back (*i);
292                         changed = true;
293                 }
294         }
295         
296         if (changed) {
297                 TracksChanged ();
298         }
299 }
300
301 void
302 Selection::add (TimeAxisView* track)
303 {
304         if (find (tracks.begin(), tracks.end(), track) == tracks.end()) {
305                 void (Selection::*pmf)(TimeAxisView*) = &Selection::remove;
306                 track->GoingAway.connect (sigc::bind (mem_fun (*this, pmf), track));
307                 tracks.push_back (track);
308                 TracksChanged();
309         }
310 }
311
312 void
313 Selection::add (RegionView* r)
314 {
315         if (find (regions.begin(), regions.end(), r) == regions.end()) {
316                 regions.add (r);
317                 RegionsChanged ();
318         }
319 }
320
321 void
322 Selection::add (vector<RegionView*>& v)
323 {
324         bool changed = false;
325
326         for (vector<RegionView*>::iterator i = v.begin(); i != v.end(); ++i) {
327                 if (find (regions.begin(), regions.end(), (*i)) == regions.end()) {
328                         regions.add ((*i));
329                         changed = true;
330                 }
331         }
332
333         if (changed) {
334                 RegionsChanged ();
335         }
336 }
337
338 long
339 Selection::add (jack_nframes_t start, jack_nframes_t end)
340 {
341         AudioRangeComparator cmp;
342
343         /* XXX this implementation is incorrect */
344
345         time.push_back (AudioRange (start, end, next_time_id++));
346         time.consolidate ();
347         time.sort (cmp);
348         
349         TimeChanged ();
350
351         return next_time_id - 1;
352 }
353
354 void
355 Selection::replace (uint32_t sid, jack_nframes_t start, jack_nframes_t end)
356 {
357         for (list<AudioRange>::iterator i = time.begin(); i != time.end(); ++i) {
358                 if ((*i).id == sid) {
359                         time.erase (i);
360                         time.push_back (AudioRange(start,end, sid));
361
362                         /* don't consolidate here */
363
364
365                         AudioRangeComparator cmp;
366                         time.sort (cmp);
367
368                         TimeChanged ();
369                         break;
370                 }
371         }
372 }
373
374 void
375 Selection::add (AutomationList* ac)
376 {
377         if (find (lines.begin(), lines.end(), ac) == lines.end()) {
378                 lines.push_back (ac);
379                 LinesChanged();
380         }
381 }
382
383 void
384 Selection::remove (Redirect* r)
385 {
386         list<Redirect*>::iterator i;
387         if ((i = find (redirects.begin(), redirects.end(), r)) != redirects.end()) {
388                 redirects.erase (i);
389                 RedirectsChanged ();
390         }
391 }
392
393 void
394 Selection::remove (TimeAxisView* track)
395 {
396         list<TimeAxisView*>::iterator i;
397         if ((i = find (tracks.begin(), tracks.end(), track)) != tracks.end()) {
398                 tracks.erase (i);
399                 TracksChanged();
400         }
401 }
402
403 void
404 Selection::remove (const list<TimeAxisView*>& track_list)
405 {
406         bool changed = false;
407
408         for (list<TimeAxisView*>::const_iterator i = track_list.begin(); i != track_list.end(); ++i) {
409
410                 list<TimeAxisView*>::iterator x;
411
412                 if ((x = find (tracks.begin(), tracks.end(), (*i))) != tracks.end()) {
413                         tracks.erase (x);
414                         changed = true;
415                 }
416         }
417
418         if (changed) {
419                 TracksChanged();
420         }
421 }
422
423 void
424 Selection::remove (Playlist* track)
425 {
426         list<Playlist*>::iterator i;
427         if ((i = find (playlists.begin(), playlists.end(), track)) != playlists.end()) {
428                 playlists.erase (i);
429                 PlaylistsChanged();
430         }
431 }
432
433 void
434 Selection::remove (const list<Playlist*>& pllist)
435 {
436         bool changed = false;
437
438         for (list<Playlist*>::const_iterator i = pllist.begin(); i != pllist.end(); ++i) {
439
440                 list<Playlist*>::iterator x;
441
442                 if ((x = find (playlists.begin(), playlists.end(), (*i))) != playlists.end()) {
443                         playlists.erase (x);
444                         changed = true;
445                 }
446         }
447
448         if (changed) {
449                 PlaylistsChanged();
450         }
451 }
452
453 void
454 Selection::remove (RegionView* r)
455 {
456         regions.remove (r);
457         RegionsChanged ();
458 }
459
460
461 void
462 Selection::remove (uint32_t selection_id)
463 {
464         if (time.empty()) {
465                 return;
466         }
467
468         for (list<AudioRange>::iterator i = time.begin(); i != time.end(); ++i) {
469                 if ((*i).id == selection_id) {
470                         time.erase (i);
471                                                 
472                         TimeChanged ();
473                         break;
474                 }
475         }
476 }
477
478 void
479 Selection::remove (jack_nframes_t start, jack_nframes_t end)
480 {
481 }
482
483 void
484 Selection::remove (AutomationList *ac)
485 {
486         list<AutomationList*>::iterator i;
487         if ((i = find (lines.begin(), lines.end(), ac)) != lines.end()) {
488                 lines.erase (i);
489                 LinesChanged();
490         }
491 }
492
493 void
494 Selection::set (Redirect *r)
495 {
496         clear_redirects ();
497         add (r);
498 }
499
500 void
501 Selection::set (TimeAxisView* track)
502 {
503         clear_tracks ();
504         add (track);
505 }
506
507 void
508 Selection::set (const list<TimeAxisView*>& track_list)
509 {
510         clear_tracks ();
511         add (track_list);
512 }
513
514 void
515 Selection::set (Playlist* playlist)
516 {
517         clear_playlists ();
518         add (playlist);
519 }
520
521 void
522 Selection::set (const list<Playlist*>& pllist)
523 {
524         clear_playlists ();
525         add (pllist);
526 }
527
528 void
529 Selection::set (RegionView* r)
530 {
531         clear_regions ();
532         add (r);
533 }
534
535 void
536 Selection::set (vector<RegionView*>& v)
537 {
538         clear_regions ();
539         // make sure to deselect any automation selections
540         clear_points();
541         add (v);
542 }
543
544 long
545 Selection::set (TimeAxisView* track, jack_nframes_t start, jack_nframes_t end)
546 {
547         if ((start == 0 && end == 0) || end < start) {
548                 return 0;
549         }
550
551         if (time.empty()) {
552                 time.push_back (AudioRange (start, end, next_time_id++));
553         } else {
554                 /* reuse the first entry, and remove all the rest */
555
556                 while (time.size() > 1) {
557                         time.pop_front();
558                 }
559                 time.front().start = start;
560                 time.front().end = end;
561         }
562
563         if (track) {
564                 time.track = track;
565                 time.group = track->edit_group();
566         } else {
567                 time.track = 0;
568                 time.group = 0;
569         }
570
571         time.consolidate ();
572
573         TimeChanged ();
574
575         return time.front().id;
576 }
577
578 void
579 Selection::set (AutomationList *ac)
580 {
581         lines.clear();
582         add (ac);
583 }
584
585 bool
586 Selection::selected (TimeAxisView* tv)
587 {
588         return find (tracks.begin(), tracks.end(), tv) != tracks.end();
589 }
590
591 bool
592 Selection::selected (RegionView* rv)
593 {
594         return find (regions.begin(), regions.end(), rv) != regions.end();
595 }
596
597 bool
598 Selection::empty ()
599 {
600         return regions.empty () &&
601                 tracks.empty () &&
602                 points.empty () && 
603                 playlists.empty () && 
604                 lines.empty () &&
605                 time.empty () &&
606                 playlists.empty () &&
607                 redirects.empty ()
608                 ;
609 }
610
611 void
612 Selection::set (list<Selectable*>& selectables)
613 {
614         clear_regions();
615         clear_points ();
616         add (selectables);
617 }
618
619 void
620 Selection::add (list<Selectable*>& selectables)
621 {
622         RegionView* rv;
623         AutomationSelectable* as;
624         vector<RegionView*> rvs;
625         vector<AutomationSelectable*> autos;
626
627         for (std::list<Selectable*>::iterator i = selectables.begin(); i != selectables.end(); ++i) {
628                 if ((rv = dynamic_cast<RegionView*> (*i)) != 0) {
629                         rvs.push_back (rv);
630                 } else if ((as = dynamic_cast<AutomationSelectable*> (*i)) != 0) {
631                         autos.push_back (as);
632                 } else {
633                         fatal << _("programming error: ")
634                               << X_("unknown selectable type passed to Selection::set()")
635                               << endmsg;
636                         /*NOTREACHED*/
637                 }
638         }
639
640         if (!rvs.empty()) {
641                 add (rvs);
642         } 
643
644         if (!autos.empty()) {
645                 add (autos);
646         } 
647 }
648
649 void
650 Selection::clear_points ()
651 {
652         if (!points.empty()) {
653                 points.clear ();
654                 PointsChanged ();
655         }
656 }
657
658 void
659 Selection::add (vector<AutomationSelectable*>& autos)
660 {
661         for (vector<AutomationSelectable*>::iterator i = autos.begin(); i != autos.end(); ++i) {
662                 points.push_back (**i);
663                 delete *i;
664         }
665
666         PointsChanged ();
667 }