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