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