Editor::transport_punch*_line has no "outline_pixels".
[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
265                 for (i = rows.begin(); i != rows.end(); ++i) {
266
267                         Region* rr = (*i)[region_list_columns.region];
268                         AudioRegion* r = dynamic_cast<AudioRegion*>(rr);
269
270                         if (r && r->whole_file()) {
271                                 
272                                 if (region->source_equivalent (*r)) {
273                                         row = *(region_list_model->append ((*i).children()));
274                                         break;
275                                 }
276                         }
277                 }
278
279                 if (i == rows.end()) {
280                         TreeModel::Row row = *(region_list_model->append());
281                 }
282
283                 
284         }
285         
286         row[region_list_columns.region] = region;
287         
288         if (region->n_channels() > 1) {
289                 row[region_list_columns.name] = string_compose("%1  [%2]", region->name(), region->n_channels());
290         } else {
291                 row[region_list_columns.name] = region->name();
292         }
293 }
294
295 void
296 Editor::region_list_selection_changed() 
297 {
298         bool sensitive;
299
300         if (region_list_display.get_selection()->count_selected_rows() > 0) {
301                 sensitive = true;
302         } else {
303                 sensitive = false;
304         }
305         
306         for (vector<Glib::RefPtr<Gtk::Action> >::iterator i = ActionManager::region_list_selection_sensitive_actions.begin(); i != ActionManager::region_list_selection_sensitive_actions.end(); ++i) {
307                 (*i)->set_sensitive (sensitive);
308         }
309
310         // GTK2FIX
311         // set_selected_regionview_from_region_list (*region, false);
312
313 }
314
315 void
316 Editor::insert_into_tmp_audio_regionlist(AudioRegion* region)
317 {
318         /* keep all whole files at the beginning */
319         
320         if (region->whole_file()) {
321                 tmp_audio_region_list.push_front (region);
322         } else {
323                 tmp_audio_region_list.push_back (region);
324         }
325 }
326
327 void
328 Editor::redisplay_regions ()
329 {
330         if (session) {
331                 
332                 region_list_display.set_model (Glib::RefPtr<Gtk::TreeStore>(0));
333                 region_list_model.clear ();
334
335                 /* now add everything we have, via a temporary list used to help with
336                    sorting.
337                 */
338                 
339                 tmp_audio_region_list.clear();
340                 session->foreach_audio_region (this, &Editor::insert_into_tmp_audio_regionlist);
341
342                 for (list<AudioRegion*>::iterator r = tmp_audio_region_list.begin(); r != tmp_audio_region_list.end(); ++r) {
343                         add_audio_region_to_region_display (*r);
344                 }
345                 
346                 region_list_display.set_model (region_list_sort_model);
347         }
348 }
349
350 void
351 Editor::region_list_clear ()
352 {
353         region_list_model->clear();
354 }
355
356 void
357 Editor::build_region_list_menu ()
358 {
359         region_list_menu = dynamic_cast<Menu*>(ActionManager::get_widget ("/RegionListMenu"));
360                                                
361         /* now grab specific menu items that we need */
362
363         toggle_full_region_list_action = ActionManager::get_action ("<Actions>/RegionList/rlShowAll");
364 }
365
366 void
367 Editor::toggle_show_auto_regions ()
368 {
369         //show_automatic_regions_in_region_list = toggle_auto_regions_item->get_active();
370         show_automatic_regions_in_region_list = true;
371         redisplay_regions ();
372 }
373
374 void
375 Editor::toggle_full_region_list ()
376 {
377         if (toggle_full_region_list_item->get_active()) {
378                 region_list_display.expand_all ();
379         } else {
380                 region_list_display.collapse_all ();
381         }
382 }
383
384 bool
385 Editor::region_list_display_key_press (GdkEventKey* ev)
386 {
387         return false;
388 }
389
390 bool
391 Editor::region_list_display_key_release (GdkEventKey* ev)
392 {
393         switch (ev->keyval) {
394         case GDK_Delete:
395                 remove_region_from_region_list ();
396                 return true;
397                 break;
398         default:
399                 break;
400         }
401
402         return false;
403 }
404
405 bool
406 Editor::region_list_display_button_press (GdkEventButton *ev)
407 {
408         Region* region;
409         TreeIter iter;
410         TreeModel::Path path;
411         TreeViewColumn* column;
412         int cellx;
413         int celly;
414
415         if (region_list_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
416                 if ((iter = region_list_model->get_iter (path))) {
417                         region = (*iter)[region_list_columns.region];
418                 }
419         }
420
421         if (region == 0) {
422                 return false;
423         }
424
425         if (Keyboard::is_delete_event (ev)) {
426                 session->remove_region_from_region_list (*region);
427                 return true;
428         }
429
430         if (Keyboard::is_context_menu_event (ev)) {
431                 if (region_list_menu == 0) {
432                         build_region_list_menu ();
433                 }
434                 region_list_menu->popup (ev->button, ev->time);
435                 return true;
436         }
437
438         switch (ev->button) {
439         case 1:
440                 /* audition on double click */
441                 if (ev->type == GDK_2BUTTON_PRESS) {
442                         consider_auditioning (*region);
443                         return true;
444                 }
445                 return false;
446                 break;
447
448         case 2:
449                 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) {
450                         consider_auditioning (*region);
451                 }
452                 return true;
453                 break;
454
455         default:
456                 break; 
457         }
458
459         return false;
460 }       
461
462 bool
463 Editor::region_list_display_button_release (GdkEventButton *ev)
464 {
465         TreeIter iter;
466         TreeModel::Path path;
467         TreeViewColumn* column;
468         int cellx;
469         int celly;
470         Region* region;
471
472         if (region_list_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
473                 if ((iter = region_list_model->get_iter (path))) {
474                         region = (*iter)[region_list_columns.region];
475                 }
476         }
477
478         if (Keyboard::is_delete_event (ev)) {
479                 session->remove_region_from_region_list (*region);
480                 return true;
481         }
482
483         switch (ev->button) {
484         case 1:
485                 return false;
486                 break;
487
488         case 3:
489                 return false;
490                 break;
491
492         default:
493                 break;
494         }
495
496         return false;
497 }
498
499 void
500 Editor::consider_auditioning (Region& region)
501 {
502         AudioRegion* r = dynamic_cast<AudioRegion*> (&region);
503
504         if (r == 0) {
505                 session->cancel_audition ();
506                 return;
507         }
508
509         if (session->is_auditioning()) {
510                 session->cancel_audition ();
511                 if (r == last_audition_region) {
512                         return;
513                 }
514         }
515
516         session->audition_region (*r);
517         last_audition_region = r;
518 }
519
520 int
521 Editor::region_list_sorter (TreeModel::iterator a, TreeModel::iterator b)
522 {
523         int cmp;
524
525         Region* r1 = (*a)[region_list_columns.region];
526         Region* r2 = (*b)[region_list_columns.region];
527
528         AudioRegion* region1 = dynamic_cast<AudioRegion*> (r1);
529         AudioRegion* region2 = dynamic_cast<AudioRegion*> (r2);
530
531         if (region1 == 0 || region2 == 0) {
532                 Glib::ustring s1;
533                 Glib::ustring s2;
534                 switch (region_list_sort_type) {
535                 case ByName:
536                         s1 = (*a)[region_list_columns.name];
537                         s2 = (*b)[region_list_columns.name];
538                         return (s1.compare (s2));
539                 default:
540                         return 0;
541                 }
542         }
543
544         switch (region_list_sort_type) {
545         case ByName:
546                 cmp = strcasecmp (region1->name().c_str(), region2->name().c_str());
547                 break;
548
549         case ByLength:
550                 cmp = region1->length() - region2->length();
551                 break;
552                 
553         case ByPosition:
554                 cmp = region1->position() - region2->position();
555                 break;
556                 
557         case ByTimestamp:
558                 cmp = region1->source().timestamp() - region2->source().timestamp();
559                 break;
560         
561         case ByStartInFile:
562                 cmp = region1->start() - region2->start();
563                 break;
564                 
565         case ByEndInFile:
566                 cmp = (region1->start() + region1->length()) - (region2->start() + region2->length());
567                 break;
568                 
569         case BySourceFileName:
570                 cmp = strcasecmp (region1->source().name().c_str(), region2->source().name().c_str());
571                 break;
572
573         case BySourceFileLength:
574                 cmp = region1->source().length() - region2->source().length();
575                 break;
576                 
577         case BySourceFileCreationDate:
578                 cmp = region1->source().timestamp() - region2->source().timestamp();
579                 break;
580
581         case BySourceFileFS:
582                 if (region1->source().name() == region2->source().name()) {
583                         cmp = strcasecmp (region1->name().c_str(),  region2->name().c_str());
584                 } else {
585                         cmp = strcasecmp (region1->source().name().c_str(),  region2->source().name().c_str());
586                 }
587                 break;
588         }
589
590         if (cmp < 0) {
591                 return -1;
592         } else if (cmp > 0) {
593                 return 1;
594         } else {
595                 return 0;
596         }
597 }
598
599 void
600 Editor::reset_region_list_sort_type (RegionListSortType type)
601 {
602         if (type != region_list_sort_type) {
603                 region_list_sort_type = type;
604
605                 switch (type) {
606                 case ByName:
607                         region_list_display.get_column (0)->set_title (_("Regions/name"));
608                         break;
609                         
610                 case ByLength:
611                         region_list_display.get_column (0)->set_title (_("Regions/length"));
612                         break;
613                         
614                 case ByPosition:
615                         region_list_display.get_column (0)->set_title (_("Regions/position"));
616                         break;
617                         
618                 case ByTimestamp:
619                         region_list_display.get_column (0)->set_title (_("Regions/creation"));
620                         break;
621                         
622                 case ByStartInFile:
623                         region_list_display.get_column (0)->set_title (_("Regions/start"));
624                         break;
625                         
626                 case ByEndInFile:
627                         region_list_display.get_column (0)->set_title (_("Regions/end"));
628                         break;
629                         
630                 case BySourceFileName:
631                         region_list_display.get_column (0)->set_title (_("Regions/file name"));
632                         break;
633                         
634                 case BySourceFileLength:
635                         region_list_display.get_column (0)->set_title (_("Regions/file size"));
636                         break;
637                         
638                 case BySourceFileCreationDate:
639                         region_list_display.get_column (0)->set_title (_("Regions/file date"));
640                         break;
641                         
642                 case BySourceFileFS:
643                         region_list_display.get_column (0)->set_title (_("Regions/file system"));
644                         break;
645                 }
646                         
647                 region_list_sort_model->set_sort_func (0, mem_fun (*this, &Editor::region_list_sorter));
648         }
649 }
650
651 void
652 Editor::reset_region_list_sort_direction (bool up)
653 {
654         // GTK2FIX
655         //region_list_display.set_sort_type (up ? GTK_SORT_ASCENDING : GTK_SORT_DESCENDING);
656         /* reset to force resort */
657         region_list_sort_model->set_sort_func (0, mem_fun (*this, &Editor::region_list_sorter));
658 }
659
660 void
661 Editor::region_list_selection_mapover (slot<void,Region&> sl)
662 {
663         Glib::RefPtr<TreeSelection> selection = region_list_display.get_selection();
664         TreeView::Selection::ListHandle_Path rows = selection->get_selected_rows ();
665         TreeView::Selection::ListHandle_Path::iterator i = rows.begin();
666
667         if (selection->count_selected_rows() == 0 || session == 0) {
668                 return;
669         }
670
671         for (; i != rows.end(); ++i) {
672                 TreeIter iter;
673
674                 if ((iter = region_list_model->get_iter (*i))) {
675                         sl (*((*iter)[region_list_columns.region]));
676                 }
677         }
678 }
679
680 void
681 Editor::hide_a_region (Region& r)
682 {
683         r.set_hidden (true);
684 }
685
686 void
687 Editor::remove_a_region (Region& r)
688 {
689         session->remove_region_from_region_list (r);
690 }
691
692 void
693 Editor::audition_region_from_region_list ()
694 {
695         region_list_selection_mapover (mem_fun (*this, &Editor::consider_auditioning));
696 }
697
698 void
699 Editor::hide_region_from_region_list ()
700 {
701         region_list_selection_mapover (mem_fun (*this, &Editor::hide_a_region));
702 }
703
704 void
705 Editor::remove_region_from_region_list ()
706 {
707         region_list_selection_mapover (mem_fun (*this, &Editor::remove_a_region));
708 }
709
710 void  
711 Editor::region_list_display_drag_data_received  (GdkDragContext     *context,
712                                                  gint                x,
713                                                  gint                y,
714                                                  GtkSelectionData   *data,
715                                                  guint               info,
716                                                  guint               time)
717 {
718         vector<string> paths;
719
720         if (convert_drop_to_paths (paths, context, x, y, data, info, time) == 0) {
721                 do_embed_sndfiles (paths, false);
722         }
723
724         gtk_drag_finish (context, TRUE, FALSE, time);
725 }