merged with 1697 revision of trunk (which is post-rc1 but pre-rc2
[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 RegionSelection::RegionSelection ()
33 {
34         RegionView::RegionViewGoingAway.connect (mem_fun(*this, &RegionSelection::remove_it));
35
36         _current_start = 0;
37         _current_end = 0;
38 }
39
40 RegionSelection::RegionSelection (const RegionSelection& other)
41 {
42         RegionView::RegionViewGoingAway.connect (mem_fun(*this, &RegionSelection::remove_it));
43
44         for (RegionSelection::const_iterator i = other.begin(); i != other.end(); ++i) {
45                 add (*i);
46         }
47         _current_start = other._current_start;
48         _current_end = other._current_end;
49 }
50
51 RegionSelection&
52 RegionSelection::operator= (const RegionSelection& other)
53 {
54         if (this != &other) {
55
56                 clear_all();
57                 
58                 for (RegionSelection::const_iterator i = other.begin(); i != other.end(); ++i) {
59                         add (*i);
60                 }
61
62                 _current_start = other._current_start;
63                 _current_end = other._current_end;
64         }
65
66         return *this;
67 }
68
69 void
70 RegionSelection::clear_all()
71 {
72         clear();
73         _bylayer.clear();
74         _current_start = 0;
75         _current_end = 0;
76 }
77
78 bool RegionSelection::contains (RegionView* rv) const
79 {
80         return find (begin(), end(), rv) != end();
81 }
82
83 bool
84 RegionSelection::add (RegionView* rv)
85 {
86         if (contains (rv)) {
87                 /* we already have it */
88                 return false;
89         }
90
91         if (rv->region()->first_frame() < _current_start || empty()) {
92                 _current_start = rv->region()->first_frame();
93         }
94         
95         if (rv->region()->last_frame() > _current_end || empty()) {
96                 _current_end = rv->region()->last_frame();
97         }
98         
99         push_back (rv);
100
101         // add to layer sorted list
102
103         add_to_layer (rv);
104
105         return true;
106 }
107
108 void
109 RegionSelection::remove_it (RegionView *rv)
110 {
111         remove (rv);
112 }
113
114 bool
115 RegionSelection::remove (RegionView* rv)
116 {
117         RegionSelection::iterator r;
118
119         if ((r = find (begin(), end(), rv)) != end()) {
120
121                 // remove from layer sorted list
122                 _bylayer.remove (rv);
123                 
124                 if (size() == 1) {
125
126                         /* this is the last one, so when we delete it
127                            we will be empty.
128                         */
129
130                         _current_start = 0;
131                         _current_end = 0;
132
133                 } else {
134                         
135                         boost::shared_ptr<Region> region ((*r)->region());
136                         
137                         if (region->first_frame() == _current_start) {
138                                 
139                                 /* reset current start */
140                                 
141                                 nframes_t ref = max_frames;
142                                 
143                                 for (RegionSelection::iterator i = begin (); i != end(); ++i) {
144                                         if (region->first_frame() < ref) {
145                                                 ref = region->first_frame();
146                                         }
147                                 }
148                                 
149                                 _current_start = ref;
150                                 
151                         }
152                         
153                         if (region->last_frame() == _current_end) {
154
155                                 /* reset current end */
156                                 
157                                 nframes_t ref = 0;
158                                 
159                                 for (RegionSelection::iterator i = begin (); i != end(); ++i) {
160                                         if (region->first_frame() > ref) {
161                                                 ref = region->first_frame();
162                                         }
163                                 }
164                                 
165                                 _current_end = ref;
166                         }
167                 }
168
169                 erase (r);
170
171                 return true;
172         }
173
174         return false;
175 }
176
177 void
178 RegionSelection::add_to_layer (RegionView * rv)
179 {
180         // insert it into layer sorted position
181
182         list<RegionView*>::iterator i;
183
184         for (i = _bylayer.begin(); i != _bylayer.end(); ++i)
185         {
186                 if (rv->region()->layer() < (*i)->region()->layer()) {
187                         _bylayer.insert(i, rv);
188                         return;
189                 }
190         }
191
192         // insert at end if we get here
193         _bylayer.insert(i, rv);
194 }
195
196 struct RegionSortByTime {
197     bool operator() (const RegionView* a, const RegionView* b) const {
198             return a->region()->position() < b->region()->position();
199     }
200 };
201
202
203 void
204 RegionSelection::by_position (list<RegionView*>& foo) const
205 {
206         list<RegionView*>::const_iterator i;
207         RegionSortByTime sorter;
208
209         for (i = _bylayer.begin(); i != _bylayer.end(); ++i) {
210                 foo.push_back (*i);
211         }
212
213         foo.sort (sorter);
214         return;
215 }
216
217 struct RegionSortByTrack {
218     bool operator() (const RegionView* a, const RegionView* b) const {
219             
220             /* really, track and position */
221
222             if (a->get_trackview().order == b->get_trackview().order) {
223                     return a->region()->position() < b->region()->position();
224             } else {
225                     return a->get_trackview().order < b->get_trackview().order;
226             }
227     }
228 };
229         
230 void
231 RegionSelection::by_track (list<RegionView*>& foo) const
232 {
233         list<RegionView*>::const_iterator i;
234         RegionSortByTrack sorter;
235
236         for (i = _bylayer.begin(); i != _bylayer.end(); ++i) {
237                 foo.push_back (*i);
238         }
239
240         foo.sort (sorter);
241         return;
242 }
243
244 void
245 RegionSelection::sort_by_position_and_track ()
246 {
247         RegionSortByTrack sorter;
248         sort (sorter);
249 }
250
251 bool
252 RegionSelection::involves (const TimeAxisView& tv) const
253 {
254         for (RegionSelection::const_iterator i = begin(); i != end(); ++i) {
255                 if (&(*i)->get_trackview() == &tv) {
256                         return true;
257                 }
258         }
259         return false;
260 }
261