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