29eac4663215aedf18fdc8a1be091ad07b221c3a
[ardour.git] / gtk2_ardour / editor_region_list.cc
1 /*
2     Copyright (C) 2000-2005 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 <cstdlib>
22 #include <cmath>
23 #include <algorithm>
24 #include <string>
25
26 #include <pbd/basename.h>
27
28 #include <ardour/audioregion.h>
29 #include <ardour/session_region.h>
30
31 #include <gtkmm2ext/stop_signal.h>
32
33 #include "editor.h"
34 #include "editing.h"
35 #include "ardour_ui.h"
36 #include "gui_thread.h"
37 #include "actions.h"
38 #include "utils.h"
39
40 #include "i18n.h"
41
42 using namespace sigc;
43 using namespace ARDOUR;
44 using namespace Gtk;
45 using namespace Glib;
46 using namespace Editing;
47
48 #define wave_cursor_width 43
49 #define wave_cursor_height 61
50 #define wave_cursor_x_hot 0
51 #define wave_cursor_y_hot 25
52 static const gchar wave_cursor_bits[] = {
53    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
54 0x00,
55    0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00,
56 0x00,
57    0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00,
58 0x00,
59    0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
60 0x00,
61    0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff,
62 0x03,
63    0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
64 0x02,
65    0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
66 0x02,
67    0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
68 0x02,
69    0x02, 0x04, 0x00, 0x00, 0x00, 0x02, 0x02, 0x04, 0x00, 0x04, 0x00,
70 0x02,
71    0x02, 0x04, 0x00, 0x04, 0x00, 0x02, 0x02, 0x0c, 0x08, 0x0c, 0x00,
72 0x02,
73    0x02, 0x1c, 0x08, 0x0c, 0x00, 0x02, 0x02, 0x1c, 0x08, 0x0c, 0x04,
74 0x02,
75    0x02, 0x3c, 0x18, 0x0c, 0x04, 0x02, 0x02, 0x7c, 0x18, 0x1c, 0x0c,
76 0x02,
77    0x82, 0xfc, 0x38, 0x1c, 0x0c, 0x02, 0xc2, 0xfc, 0x78, 0x3c, 0x1c,
78 0x02,
79    0xe2, 0xfd, 0xf9, 0x7d, 0x1c, 0x02, 0xf2, 0xff, 0xfb, 0xff, 0x1c,
80 0x02,
81    0xfa, 0xff, 0xfb, 0xff, 0x3f, 0x02, 0xfe, 0xff, 0xff, 0xff, 0xff,
82 0x03,
83    0xfe, 0xff, 0xff, 0xff, 0xff, 0x03, 0xfa, 0xff, 0xff, 0xff, 0x3f,
84 0x02,
85    0xf2, 0xff, 0xfb, 0xfd, 0x3c, 0x02, 0xe2, 0xfd, 0x7b, 0x7c, 0x1c,
86 0x02,
87    0xc2, 0xfc, 0x39, 0x3c, 0x1c, 0x02, 0x82, 0xfc, 0x18, 0x1c, 0x1c,
88 0x02,
89    0x02, 0xfc, 0x18, 0x1c, 0x0c, 0x02, 0x02, 0x7c, 0x18, 0x0c, 0x0c,
90 0x02,
91    0x02, 0x3c, 0x08, 0x0c, 0x04, 0x02, 0x02, 0x1c, 0x08, 0x0c, 0x04,
92 0x02,
93    0x02, 0x1c, 0x08, 0x0c, 0x00, 0x02, 0x02, 0x0c, 0x00, 0x04, 0x00,
94 0x02,
95    0x02, 0x04, 0x00, 0x04, 0x00, 0x02, 0x02, 0x04, 0x00, 0x00, 0x00,
96 0x02,
97    0x02, 0x04, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
98 0x02,
99    0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
100 0x02,
101    0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
102 0x02,
103    0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0xfe, 0xff, 0xff, 0xff, 0xff,
104 0x03,
105    0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
106 0x00,
107    0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00,
108 0x00,
109    0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00,
110 0x00,
111    0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
112 0x00,
113    0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
114
115 #define wave_cursor_mask_width 43
116 #define wave_cursor_mask_height 61
117 #define wave_cursor_mask_x_hot 0
118 #define wave_cursor_mask_y_hot 25
119 static const gchar wave_cursor_mask_bits[] = {
120    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
121 0x00,
122    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
123 0x00,
124    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
125 0x00,
126    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
127 0x00,
128    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
129 0x00,
130    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
131 0x00,
132    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
133 0x00,
134    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
135 0x00,
136    0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00,
137 0x00,
138    0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x08, 0x0c, 0x00,
139 0x00,
140    0x00, 0x1c, 0x08, 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x0c, 0x04,
141 0x00,
142    0x00, 0x3c, 0x18, 0x0c, 0x04, 0x00, 0x00, 0x7c, 0x18, 0x1c, 0x0c,
143 0x00,
144    0x80, 0xfc, 0x38, 0x1c, 0x0c, 0x00, 0xc0, 0xfc, 0x78, 0x3c, 0x1c,
145 0x00,
146    0xe0, 0xfd, 0xf9, 0x7d, 0x1c, 0x00, 0xf0, 0xff, 0xfb, 0xff, 0x1c,
147 0x00,
148    0xf8, 0xff, 0xfb, 0xff, 0x3f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
149 0x07,
150    0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xf8, 0xff, 0xff, 0xff, 0x3f,
151 0x00,
152    0xf0, 0xff, 0xfb, 0xfd, 0x3c, 0x00, 0xe0, 0xfd, 0x7b, 0x7c, 0x1c,
153 0x00,
154    0xc0, 0xfc, 0x39, 0x3c, 0x1c, 0x00, 0x80, 0xfc, 0x18, 0x1c, 0x1c,
155 0x00,
156    0x00, 0xfc, 0x18, 0x1c, 0x0c, 0x00, 0x00, 0x7c, 0x18, 0x0c, 0x0c,
157 0x00,
158    0x00, 0x3c, 0x08, 0x0c, 0x04, 0x00, 0x00, 0x1c, 0x08, 0x0c, 0x04,
159 0x00,
160    0x00, 0x1c, 0x08, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x04, 0x00,
161 0x00,
162    0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
163 0x00,
164    0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
165 0x00,
166    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
167 0x00,
168    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
169 0x00,
170    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
171 0x00,
172    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
173 0x00,
174    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
175 0x00,
176    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
177 0x00,
178    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
179 0x00,
180    0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
181
182 GdkCursor *wave_cursor = 0;
183
184 void
185 Editor::handle_audio_region_removed (AudioRegion* ignored)
186 {
187         redisplay_regions ();
188 }
189
190 void
191 Editor::handle_new_audio_region (AudioRegion *region)
192 {
193         /* don't copy region - the one we are being notified
194            about belongs to the session, and so it will
195            never be edited.
196         */
197         add_audio_region_to_region_display (region);
198 }
199
200 void
201 Editor::region_hidden (Region* r)
202 {
203         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::region_hidden), r));    
204
205         redisplay_regions ();
206 }
207
208 void
209 Editor::add_audio_region_to_region_display (AudioRegion *region)
210 {
211         string str;
212         TreeModel::Row row;
213         Gdk::Color c;
214
215         if (!show_automatic_regions_in_region_list && region->automatic()) {
216                 return;
217         }
218
219         if (region->hidden()) {
220
221                 TreeModel::iterator iter = region_list_model->get_iter (_("/Hidden"));
222                 TreeModel::Row parent;
223                 TreeModel::Row child;
224
225                 if (iter == region_list_model->children().end()) {
226                         
227                         parent = *(region_list_model->append());
228                         
229                         parent[region_list_columns.name] = _("Hidden");
230                         parent[region_list_columns.region] = 0;
231                 } else {
232                         parent = *iter;
233                 }
234
235                 row = *(region_list_model->append (parent.children()));
236
237         } else if (region->whole_file()) {
238
239                 TreeModel::Row row = *(region_list_model->append());
240
241                 if (region->source().name()[0] == '/') { // external file
242
243                         if (region->whole_file()) {
244                                 str = ".../";
245                                 str += PBD::basename_nosuffix (region->source().name());
246                                 
247                         } else {
248                                 str = region->name();
249                         }
250
251                 } else {
252
253                         str = region->name();
254
255                 }
256
257                 row[region_list_columns.name] = str;
258                 row[region_list_columns.region] = region;
259
260                 return;
261                 
262         } else {
263
264                 /* find parent node, add as new child */
265                 
266                 TreeModel::iterator i;
267                 TreeModel::Children rows = region_list_model->children();
268                 bool found_parent = false;
269
270                 for (i = rows.begin(); i != rows.end(); ++i) {
271
272                         Region* rr = (*i)[region_list_columns.region];
273                         AudioRegion* r = dynamic_cast<AudioRegion*>(rr);
274
275                         if (r && r->whole_file()) {
276                                 if (region->source_equivalent (*r)) {
277                                         row = *(region_list_model->append ((*i).children()));
278                                         set_color(c, 65535, 0, 0);
279                                         row[region_list_columns.color_] = c;
280                                         found_parent = true;
281                                         break;
282                                 }
283                         }
284                 }
285
286                 if (!found_parent) {
287                         row = *(region_list_model->append());
288                 }
289
290                 
291         }
292         
293         row[region_list_columns.region] = region;
294         
295         if (region->n_channels() > 1) {
296                 row[region_list_columns.name] = string_compose("%1  [%2]", region->name(), region->n_channels());
297         } else {
298                 row[region_list_columns.name] = region->name();
299         }
300 }
301
302 void
303 Editor::region_list_selection_changed() 
304 {
305         bool selected;
306
307         if (region_list_display.get_selection()->count_selected_rows() > 0) {
308                 selected = true;
309         } else {
310                 selected = false;
311         }
312         
313         if (selected) {
314                 TreeView::Selection::ListHandle_Path rows = region_list_display.get_selection()->get_selected_rows ();
315                 TreeView::Selection::ListHandle_Path::iterator i = rows.begin();
316                 TreeIter iter;
317
318                 /* just set the first selected region (in fact, the selection model might be SINGLE, which
319                    means there can only be one.
320                 */
321                 
322                 if ((iter = region_list_model->get_iter (*i))) {
323                         set_selected_regionview_from_region_list (*((*iter)[region_list_columns.region]), false);
324                 }
325         }
326 }
327
328 void
329 Editor::insert_into_tmp_audio_regionlist(AudioRegion* region)
330 {
331         /* keep all whole files at the beginning */
332         
333         if (region->whole_file()) {
334                 tmp_audio_region_list.push_front (region);
335         } else {
336                 tmp_audio_region_list.push_back (region);
337         }
338 }
339
340 void
341 Editor::redisplay_regions ()
342 {
343         if (session) {
344
345                 region_list_display.set_model (Glib::RefPtr<Gtk::TreeStore>(0));
346                 region_list_model->clear ();
347
348                 /* now add everything we have, via a temporary list used to help with
349                    sorting.
350                 */
351                 
352                 tmp_audio_region_list.clear();
353                 session->foreach_audio_region (this, &Editor::insert_into_tmp_audio_regionlist);
354
355                 for (list<AudioRegion*>::iterator r = tmp_audio_region_list.begin(); r != tmp_audio_region_list.end(); ++r) {
356                         add_audio_region_to_region_display (*r);
357                 }
358                 
359                 region_list_display.set_model (region_list_model);
360         }
361 }
362
363 void
364 Editor::region_list_clear ()
365 {
366         region_list_model->clear();
367 }
368
369 void
370 Editor::build_region_list_menu ()
371 {
372         region_list_menu = dynamic_cast<Menu*>(ActionManager::get_widget ("/RegionListMenu"));
373                                                
374         /* now grab specific menu items that we need */
375
376         toggle_full_region_list_action = ActionManager::get_action (X_("RegionList"), X_("rlShowAll"));
377 }
378
379 void
380 Editor::toggle_show_auto_regions ()
381 {
382         //show_automatic_regions_in_region_list = toggle_auto_regions_item->get_active();
383         show_automatic_regions_in_region_list = true;
384         redisplay_regions ();
385 }
386
387 void
388 Editor::toggle_full_region_list ()
389 {
390         if (toggle_full_region_list_item->get_active()) {
391                 region_list_display.expand_all ();
392         } else {
393                 region_list_display.collapse_all ();
394         }
395 }
396
397 void
398 Editor::show_region_list_display_context_menu (int button, int time)
399 {
400         if (region_list_menu == 0) {
401                 build_region_list_menu ();
402         }
403
404         if (region_list_display.get_selection()->count_selected_rows() > 0) {
405                 ActionManager::set_sensitive (ActionManager::region_list_selection_sensitive_actions, true);
406         } else {
407                 ActionManager::set_sensitive (ActionManager::region_list_selection_sensitive_actions, false);
408         }
409
410         region_list_menu->popup (button, time);
411 }
412
413 bool
414 Editor::region_list_display_key_press (GdkEventKey* ev)
415 {
416         return false;
417 }
418
419 bool
420 Editor::region_list_display_key_release (GdkEventKey* ev)
421 {
422         switch (ev->keyval) {
423         case GDK_Delete:
424                 remove_region_from_region_list ();
425                 return true;
426                 break;
427         default:
428                 break;
429         }
430
431         return false;
432 }
433
434 bool
435 Editor::region_list_display_button_press (GdkEventButton *ev)
436 {
437         Region* region;
438         TreeIter iter;
439         TreeModel::Path path;
440         TreeViewColumn* column;
441         int cellx;
442         int celly;
443
444         cerr << "RL button press\n";
445
446         if (region_list_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
447                 if ((iter = region_list_model->get_iter (path))) {
448                         region = (*iter)[region_list_columns.region];
449                 }
450         }
451
452         if (region == 0) {
453                 return false;
454         }
455
456         if (Keyboard::is_delete_event (ev)) {
457                 session->remove_region_from_region_list (*region);
458                 return true;
459         }
460
461         if (Keyboard::is_context_menu_event (ev)) {
462                 show_region_list_display_context_menu (ev->button, ev->time);
463                 return true;
464         }
465
466         switch (ev->button) {
467         case 1:
468                 /* audition on double click */
469                 if (ev->type == GDK_2BUTTON_PRESS) {
470                         consider_auditioning (*region);
471                         return true;
472                 }
473                 return false;
474                 break;
475
476         case 2:
477                 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) {
478                         consider_auditioning (*region);
479                 }
480                 return true;
481                 break;
482
483         default:
484                 break; 
485         }
486
487         return false;
488 }       
489
490 bool
491 Editor::region_list_display_button_release (GdkEventButton *ev)
492 {
493         TreeIter iter;
494         TreeModel::Path path;
495         TreeViewColumn* column;
496         int cellx;
497         int celly;
498         Region* region;
499
500         cerr << "RL button release\n";
501
502         if (region_list_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
503                 if ((iter = region_list_model->get_iter (path))) {
504                         region = (*iter)[region_list_columns.region];
505                 }
506         }
507
508         if (Keyboard::is_delete_event (ev)) {
509                 session->remove_region_from_region_list (*region);
510                 return true;
511         }
512
513         switch (ev->button) {
514         case 1:
515                 return false;
516                 break;
517
518         case 3:
519                 return false;
520                 break;
521
522         default:
523                 break;
524         }
525
526         return false;
527 }
528
529 void
530 Editor::consider_auditioning (Region& region)
531 {
532         AudioRegion* r = dynamic_cast<AudioRegion*> (&region);
533
534         if (r == 0) {
535                 session->cancel_audition ();
536                 return;
537         }
538
539         if (session->is_auditioning()) {
540                 session->cancel_audition ();
541                 if (r == last_audition_region) {
542                         return;
543                 }
544         }
545
546         session->audition_region (*r);
547         last_audition_region = r;
548 }
549
550 int
551 Editor::region_list_sorter (TreeModel::iterator a, TreeModel::iterator b)
552 {
553         int cmp;
554
555         Region* r1 = (*a)[region_list_columns.region];
556         Region* r2 = (*b)[region_list_columns.region];
557
558         AudioRegion* region1 = dynamic_cast<AudioRegion*> (r1);
559         AudioRegion* region2 = dynamic_cast<AudioRegion*> (r2);
560
561         if (region1 == 0 || region2 == 0) {
562                 Glib::ustring s1;
563                 Glib::ustring s2;
564                 switch (region_list_sort_type) {
565                 case ByName:
566                         s1 = (*a)[region_list_columns.name];
567                         s2 = (*b)[region_list_columns.name];
568                         return (s1.compare (s2));
569                 default:
570                         return 0;
571                 }
572         }
573
574         switch (region_list_sort_type) {
575         case ByName:
576                 cmp = strcasecmp (region1->name().c_str(), region2->name().c_str());
577                 break;
578
579         case ByLength:
580                 cmp = region1->length() - region2->length();
581                 break;
582                 
583         case ByPosition:
584                 cmp = region1->position() - region2->position();
585                 break;
586                 
587         case ByTimestamp:
588                 cmp = region1->source().timestamp() - region2->source().timestamp();
589                 break;
590         
591         case ByStartInFile:
592                 cmp = region1->start() - region2->start();
593                 break;
594                 
595         case ByEndInFile:
596                 cmp = (region1->start() + region1->length()) - (region2->start() + region2->length());
597                 break;
598                 
599         case BySourceFileName:
600                 cmp = strcasecmp (region1->source().name().c_str(), region2->source().name().c_str());
601                 break;
602
603         case BySourceFileLength:
604                 cmp = region1->source().length() - region2->source().length();
605                 break;
606                 
607         case BySourceFileCreationDate:
608                 cmp = region1->source().timestamp() - region2->source().timestamp();
609                 break;
610
611         case BySourceFileFS:
612                 if (region1->source().name() == region2->source().name()) {
613                         cmp = strcasecmp (region1->name().c_str(),  region2->name().c_str());
614                 } else {
615                         cmp = strcasecmp (region1->source().name().c_str(),  region2->source().name().c_str());
616                 }
617                 break;
618         }
619
620         if (cmp < 0) {
621                 return -1;
622         } else if (cmp > 0) {
623                 return 1;
624         } else {
625                 return 0;
626         }
627 }
628
629 void
630 Editor::reset_region_list_sort_type (RegionListSortType type)
631 {
632         if (type != region_list_sort_type) {
633                 region_list_sort_type = type;
634                 region_list_sort_model->set_sort_func (0, mem_fun (*this, &Editor::region_list_sorter));
635         }
636 }
637
638 void
639 Editor::reset_region_list_sort_direction (bool up)
640 {
641         // region_list_display.set_sort_type (up ? GTK_SORT_ASCENDING : GTK_SORT_DESCENDING);
642 }
643
644 void
645 Editor::region_list_selection_mapover (slot<void,Region&> sl)
646 {
647         Glib::RefPtr<TreeSelection> selection = region_list_display.get_selection();
648         TreeView::Selection::ListHandle_Path rows = selection->get_selected_rows ();
649         TreeView::Selection::ListHandle_Path::iterator i = rows.begin();
650
651         if (selection->count_selected_rows() == 0 || session == 0) {
652                 return;
653         }
654
655         for (; i != rows.end(); ++i) {
656                 TreeIter iter;
657
658                 if ((iter = region_list_model->get_iter (*i))) {
659                         sl (*((*iter)[region_list_columns.region]));
660                 }
661         }
662 }
663
664 void
665 Editor::hide_a_region (Region& r)
666 {
667         r.set_hidden (true);
668 }
669
670 void
671 Editor::remove_a_region (Region& r)
672 {
673         session->remove_region_from_region_list (r);
674 }
675
676 void
677 Editor::audition_region_from_region_list ()
678 {
679         region_list_selection_mapover (mem_fun (*this, &Editor::consider_auditioning));
680 }
681
682 void
683 Editor::hide_region_from_region_list ()
684 {
685         region_list_selection_mapover (mem_fun (*this, &Editor::hide_a_region));
686 }
687
688 void
689 Editor::remove_region_from_region_list ()
690 {
691         region_list_selection_mapover (mem_fun (*this, &Editor::remove_a_region));
692 }
693
694 void  
695 Editor::region_list_display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
696                                                 int x, int y, 
697                                                 const SelectionData& data,
698                                                 guint info, guint time)
699 {
700         vector<string> paths;
701
702         if (convert_drop_to_paths (paths, context, x, y, data, info, time) == 0) {
703                 do_embed_sndfiles (paths, false);
704                 context->drag_finish (true, false, time);
705         }
706 }
707