*** NEW CODING POLICY ***
[ardour.git] / gtk2_ardour / region_selection.cc
1 /*
2     Copyright (C) 2006 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 #include <algorithm>
20
21 #include "ardour/region.h"
22
23 #include "region_view.h"
24 #include "region_selection.h"
25 #include "time_axis_view.h"
26
27 using namespace ARDOUR;
28 using namespace PBD;
29 using namespace sigc;
30
31 /**
32  *  Construct an empty RegionSelection.
33  */
34
35 RegionSelection::RegionSelection ()
36 {
37         RegionView::RegionViewGoingAway.connect (mem_fun(*this, &RegionSelection::remove_it));
38
39         _current_start = 0;
40         _current_end = 0;
41 }
42
43 /**
44  *  Copy constructor.
45  *  @param other RegionSelection to copy.
46  */
47
48 RegionSelection::RegionSelection (const RegionSelection& other)
49 {
50         RegionView::RegionViewGoingAway.connect (mem_fun(*this, &RegionSelection::remove_it));
51
52         for (RegionSelection::const_iterator i = other.begin(); i != other.end(); ++i) {
53                 add (*i);
54         }
55         _current_start = other._current_start;
56         _current_end = other._current_end;
57 }
58
59 /**
60  *  operator= to set a RegionSelection to be the same as another.
61  *  @param other Other RegionSelection.
62  */
63
64 RegionSelection&
65 RegionSelection::operator= (const RegionSelection& other)
66 {
67         if (this != &other) {
68
69                 clear_all();
70                 
71                 for (RegionSelection::const_iterator i = other.begin(); i != other.end(); ++i) {
72                         add (*i);
73                 }
74
75                 _current_start = other._current_start;
76                 _current_end = other._current_end;
77         }
78
79         return *this;
80 }
81
82 /**
83  *  Empty this RegionSelection.
84  */
85
86 void
87 RegionSelection::clear_all()
88 {
89         clear();
90         _bylayer.clear();
91         _current_start = 0;
92         _current_end = 0;
93 }
94
95 /**
96  *  @param rv RegionView.
97  *  @return true if this selection contains rv.
98  */
99
100 bool RegionSelection::contains (RegionView* rv) const
101 {
102         return find (begin(), end(), rv) != end();
103 }
104
105 /**
106  *  Add a region to the selection.
107  *  @param rv Region to add.
108  *  @return false if we already had the region, otherwise true.
109  */
110
111 bool
112 RegionSelection::add (RegionView* rv)
113 {
114         if (contains (rv)) {
115                 /* we already have it */
116                 return false;
117         }
118
119         if (rv->region()->first_frame() < _current_start || empty()) {
120                 _current_start = rv->region()->first_frame();
121         }
122         
123         if (rv->region()->last_frame() > _current_end || empty()) {
124                 _current_end = rv->region()->last_frame();
125         }
126         
127         push_back (rv);
128
129         /* add to layer sorted list */
130
131         add_to_layer (rv);
132
133         return true;
134 }
135
136 /**
137  *  Remove a region from the selection.
138  *  @param rv Region to remove.
139  */
140
141 void
142 RegionSelection::remove_it (RegionView *rv)
143 {
144         remove (rv);
145 }
146
147 /**
148  *  Remove a region from the selection.
149  *  @param rv Region to remove.
150  *  @return true if the region was in the selection, false if not.
151  */
152
153 bool
154 RegionSelection::remove (RegionView* rv)
155 {
156         RegionSelection::iterator r;
157
158         if ((r = find (begin(), end(), rv)) != end()) {
159
160                 // remove from layer sorted list
161                 _bylayer.remove (rv);
162                 
163                 if (size() == 1) {
164
165                         /* this is the last one, so when we delete it
166                            we will be empty.
167                         */
168
169                         _current_start = 0;
170                         _current_end = 0;
171
172                 } else {
173                         
174                         boost::shared_ptr<Region> region ((*r)->region());
175                         
176                         if (region->first_frame() == _current_start) {
177                                 
178                                 /* reset current start */
179                                 
180                                 nframes_t ref = max_frames;
181                                 
182                                 for (RegionSelection::iterator i = begin (); i != end(); ++i) {
183                                         if (region->first_frame() < ref) {
184                                                 ref = region->first_frame();
185                                         }
186                                 }
187                                 
188                                 _current_start = ref;
189                                 
190                         }
191                         
192                         if (region->last_frame() == _current_end) {
193
194                                 /* reset current end */
195                                 
196                                 nframes_t ref = 0;
197                                 
198                                 for (RegionSelection::iterator i = begin (); i != end(); ++i) {
199                                         if (region->first_frame() > ref) {
200                                                 ref = region->first_frame();
201                                         }
202                                 }
203                                 
204                                 _current_end = ref;
205                         }
206                 }
207
208                 erase (r);
209
210                 return true;
211         }
212
213         return false;
214 }
215
216 /**
217  *  Add a region to the list sorted by layer.
218  *  @param rv Region to add.
219  */
220
221 void
222 RegionSelection::add_to_layer (RegionView * rv)
223 {
224         // insert it into layer sorted position
225
226         list<RegionView*>::iterator i;
227
228         for (i = _bylayer.begin(); i != _bylayer.end(); ++i)
229         {
230                 if (rv->region()->layer() < (*i)->region()->layer()) {
231                         _bylayer.insert(i, rv);
232                         return;
233                 }
234         }
235
236         // insert at end if we get here
237         _bylayer.insert(i, rv);
238 }
239
240 struct RegionSortByTime {
241     bool operator() (const RegionView* a, const RegionView* b) const {
242             return a->region()->position() < b->region()->position();
243     }
244 };
245
246
247 /**
248  *  @param foo List which will be filled with the selection's regions
249  *  sorted by position.
250  */
251
252 void
253 RegionSelection::by_position (list<RegionView*>& foo) const
254 {
255         list<RegionView*>::const_iterator i;
256         RegionSortByTime sorter;
257
258         for (i = _bylayer.begin(); i != _bylayer.end(); ++i) {
259                 foo.push_back (*i);
260         }
261
262         foo.sort (sorter);
263         return;
264 }
265
266 struct RegionSortByTrack {
267     bool operator() (const RegionView* a, const RegionView* b) const {
268             
269             /* really, track and position */
270
271             if (a->get_trackview().order() == b->get_trackview().order()) {
272                     return a->region()->position() < b->region()->position();
273             } else {
274                     return a->get_trackview().order() < b->get_trackview().order();
275             }
276     }
277 };
278
279
280 /**
281  *  @param List which will be filled with the selection's regions
282  *  sorted by track and position.
283  */
284
285 void
286 RegionSelection::by_track (list<RegionView*>& foo) const
287 {
288         list<RegionView*>::const_iterator i;
289         RegionSortByTrack sorter;
290
291         for (i = _bylayer.begin(); i != _bylayer.end(); ++i) {
292                 foo.push_back (*i);
293         }
294
295         foo.sort (sorter);
296         return;
297 }
298
299 /**
300  *  @param Sort the selection by position and track.
301  */
302
303 void
304 RegionSelection::sort_by_position_and_track ()
305 {
306         RegionSortByTrack sorter;
307         sort (sorter);
308 }
309
310 /**
311  *  @param tv Track.
312  *  @return true if any of the selection's regions are on tv.
313  */
314
315 bool
316 RegionSelection::involves (const TimeAxisView& tv) const
317 {
318         for (RegionSelection::const_iterator i = begin(); i != end(); ++i) {
319                 if (&(*i)->get_trackview() == &tv) {
320                         return true;
321                 }
322         }
323         return false;
324 }
325