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