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