ctrl_toggle preference, dblclk select single group/edit, update shortcuts
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / edit.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "asset.h"
23 #include "assets.h"
24 #include "bcsignals.h"
25 #include "clip.h"
26 #include "edit.h"
27 #include "edits.h"
28 #include "edl.h"
29 #include "edlsession.h"
30 #include "filexml.h"
31 #include "filesystem.h"
32 #include "localsession.h"
33 #include "plugin.h"
34 #include "mainsession.h"
35 #include "strack.h"
36 #include "trackcanvas.h"
37 #include "tracks.h"
38 #include "transition.h"
39 #include <string.h>
40
41
42 Edit::Edit()
43 {
44         reset();
45 }
46
47 Edit::Edit(EDL *edl, Track *track)
48 {
49         reset();
50         this->edl = edl;
51         this->track = track;
52         if(track) this->edits = track->edits;
53         id = EDL::next_id();
54 }
55
56 Edit::Edit(EDL *edl, Edits *edits)
57 {
58         reset();
59         this->edl = edl;
60         this->edits = edits;
61         if(edits) this->track = edits->track;
62         id = EDL::next_id();
63 }
64
65 Edit::~Edit()
66 {
67 //printf("Edit::~Edit 1\n");
68         if(transition) delete transition;
69 //printf("Edit::~Edit 2\n");
70 }
71
72 void Edit::reset()
73 {
74         edl = 0;
75         track = 0;
76         edits = 0;
77         startsource = 0;
78         startproject = 0;
79         length = 0;
80         asset = 0;
81         transition = 0;
82         channel = 0;
83         user_title[0] = 0;
84         nested_edl = 0;
85         is_plugin = 0;
86         is_selected = 0;
87         hard_left = 0;
88         hard_right = 0;
89         color = 0;
90         group_id = 0;
91 }
92
93 Indexable* Edit::get_source()
94 {
95         if(asset) return asset;
96         if(nested_edl) return nested_edl;
97         return 0;
98 }
99
100 int Edit::copy(int64_t start,
101         int64_t end,
102         FileXML *file,
103         const char *output_path)
104 {
105 // variables
106 //printf("Edit::copy 1\n");
107
108         int64_t endproject = startproject + length;
109         int result;
110
111         if((startproject >= start && startproject <= end) ||  // startproject in range
112                  (endproject <= end && endproject >= start) ||     // endproject in range
113                  (startproject <= start && endproject >= end))    // range in project
114         {
115 // edit is in range
116                 int64_t startproject_in_selection = startproject; // start of edit in selection in project
117                 int64_t startsource_in_selection = startsource; // start of source in selection in source
118                 //int64_t endsource_in_selection = startsource + length; // end of source in selection
119                 int64_t length_in_selection = length;             // length of edit in selection
120 //printf("Edit::copy 2\n");
121
122                 if(startproject < start)
123                 {         // start is after start of edit in project
124                         int64_t length_difference = start - startproject;
125
126                         startsource_in_selection += length_difference;
127                         startproject_in_selection += length_difference;
128                         length_in_selection -= length_difference;
129                 }
130 //printf("Edit::copy 3\n");
131
132                 if(endproject > end)
133                 {         // end is before end of edit in project
134                         length_in_selection = end - startproject_in_selection;
135                 }
136
137 //printf("Edit::copy 4\n");
138                 if(file)    // only if not counting
139                 {
140                         file->tag.set_title("EDIT");
141                         file->tag.set_property("STARTSOURCE", startsource_in_selection);
142                         file->tag.set_property("CHANNEL", (int64_t)channel);
143                         file->tag.set_property("LENGTH", length_in_selection);
144                         file->tag.set_property("HARD_LEFT", hard_left);
145                         file->tag.set_property("HARD_RIGHT", hard_right);
146                         file->tag.set_property("COLOR", color);
147                         file->tag.set_property("GROUP_ID", group_id);
148                         if(user_title[0]) file->tag.set_property("USER_TITLE", user_title);
149 //printf("Edit::copy 5\n");
150
151                         copy_properties_derived(file, length_in_selection);
152
153                         file->append_tag();
154 //                      file->append_newline();
155 //printf("Edit::copy 6\n");
156
157                         if(nested_edl)
158                         {
159                                 file->tag.set_title("NESTED_EDL");
160                                 file->tag.set_property("SRC", nested_edl->path);
161                                 file->append_tag();
162                                 file->tag.set_title("/NESTED_EDL");
163                                 file->append_tag();
164                                 file->append_newline();
165                         }
166
167                         if(asset)
168                         {
169 //printf("Edit::copy 6 %s\n", asset->path);
170                                 char stored_path[BCTEXTLEN];
171                                 char asset_directory[BCTEXTLEN];
172                                 char output_directory[BCTEXTLEN];
173                                 FileSystem fs;
174
175 //printf("Edit::copy %d %s\n", __LINE__, asset->path);
176                                 fs.extract_dir(asset_directory, asset->path);
177 //printf("Edit::copy %d %s\n", __LINE__, asset->path);
178
179                                 if(output_path)
180                                         fs.extract_dir(output_directory, output_path);
181                                 else
182                                         output_directory[0] = 0;
183 //printf("Edit::copy %s, %s %s, %s\n", asset->path, asset_directory, output_path, output_directory);
184
185                                 if(output_path && !strcmp(asset_directory, output_directory))
186                                         fs.extract_name(stored_path, asset->path);
187                                 else
188                                         strcpy(stored_path, asset->path);
189
190                                 file->tag.set_title("FILE");
191                                 file->tag.set_property("SRC", stored_path);
192                                 file->append_tag();
193                                 file->tag.set_title("/FILE");
194                                 file->append_tag();
195                         }
196
197                         if(transition && startsource_in_selection == startsource)
198                         {
199                                 transition->save_xml(file);
200                         }
201
202 //printf("Edit::copy 7\n");
203                         file->tag.set_title("/EDIT");
204                         file->append_tag();
205                         file->append_newline();
206 //printf("Edit::copy 8\n");
207                 }
208 //printf("Edit::copy 9\n");
209                 result = 1;
210         }
211         else
212         {
213                 result = 0;
214         }
215 //printf("Edit::copy 10\n");
216         return result;
217 }
218
219
220 int64_t Edit::get_source_end(int64_t default_)
221 {
222         return default_;
223 }
224
225 void Edit::insert_transition(char *title)
226 {
227 //printf("Edit::insert_transition this=%p title=%p title=%s\n", this, title, title);
228         delete transition;
229         transition = new Transition(edl, this, title,
230                 track->to_units(edl->session->default_transition_length, 1));
231 }
232
233 void Edit::detach_transition()
234 {
235         if(transition) delete transition;
236         transition = 0;
237 }
238
239 int Edit::silence()
240 {
241         return (track->data_type != TRACK_SUBTITLE ?
242                 asset || nested_edl :
243                 *((SEdit *)this)->get_text()) ? 0 : 1;
244 }
245 void Edit::mute()
246 {
247         if( track->data_type != TRACK_SUBTITLE ) {
248                 asset = 0;
249                 nested_edl = 0;
250         }
251         else
252                 *((SEdit *)this)->get_text() = 0;
253 }
254
255 void Edit::set_selected(int v)
256 {
257         if( group_id )
258                 edl->tracks->set_group_selected(group_id, v);
259         else
260                 is_selected = v >= 0 ? v : !is_selected ? 1 : 0;
261 }
262
263 void Edit::copy_from(Edit *edit)
264 {
265         this->nested_edl = edl->nested_edls.get_nested(edit->nested_edl);
266         this->asset = edl->assets->update(edit->asset);
267         this->startsource = edit->startsource;
268         this->startproject = edit->startproject;
269         this->length = edit->length;
270         this->hard_left = edit->hard_left;
271         this->hard_right = edit->hard_right;
272         this->color = edit->color;
273         this->group_id = edit->group_id;
274         strcpy (this->user_title, edit->user_title);
275
276         if(edit->transition)
277         {
278                 if(!transition) transition = new Transition(edl,
279                         this,
280                         edit->transition->title,
281                         edit->transition->length);
282                 *this->transition = *edit->transition;
283         }
284         this->channel = edit->channel;
285 }
286
287 void Edit::equivalent_output(Edit *edit, int64_t *result)
288 {
289 // End of edit changed
290         if(startproject + length != edit->startproject + edit->length)
291         {
292                 int64_t new_length = MIN(startproject + length,
293                         edit->startproject + edit->length);
294                 if(*result < 0 || new_length < *result)
295                         *result = new_length;
296         }
297
298         if(
299 // Different nested EDLs
300                 (edit->nested_edl && !nested_edl) ||
301                 (!edit->nested_edl && nested_edl) ||
302 // Different assets
303                 (edit->asset == 0 && asset != 0) ||
304                 (edit->asset != 0 && asset == 0) ||
305 // different transitions
306                 (edit->transition == 0 && transition != 0) ||
307                 (edit->transition != 0 && transition == 0) ||
308 // Position changed
309                 (startproject != edit->startproject) ||
310                 (startsource != edit->startsource) ||
311 // Transition changed
312                 (transition && edit->transition &&
313                         !transition->identical(edit->transition)) ||
314 // Asset changed
315                 (asset && edit->asset &&
316                         !asset->equivalent(*edit->asset, 1, 1, edl)) ||
317 // Nested EDL changed
318                 (nested_edl && edit->nested_edl &&
319                         strcmp(nested_edl->path, edit->nested_edl->path))
320                 )
321         {
322 // Start of edit changed
323                 if(*result < 0 || startproject < *result) *result = startproject;
324         }
325 }
326
327
328 Edit& Edit::operator=(Edit& edit)
329 {
330 //printf("Edit::operator= called\n");
331         copy_from(&edit);
332         return *this;
333 }
334
335 void Edit::synchronize_params(Edit *edit)
336 {
337         copy_from(edit);
338 }
339
340
341 // Comparison for ResourcePixmap drawing
342 int Edit::identical(Edit &edit)
343 {
344         int result = (this->nested_edl == edit.nested_edl &&
345                 this->asset == edit.asset &&
346                 this->startsource == edit.startsource &&
347                 this->startproject == edit.startproject &&
348                 this->length == edit.length &&
349                 this->transition == edit.transition &&
350                 this->channel == edit.channel);
351         return result;
352 }
353
354 int Edit::operator==(Edit &edit)
355 {
356         return identical(edit);
357 }
358
359 double Edit::frames_per_picon()
360 {
361         return Units::round(picon_w()) / frame_w();
362 }
363
364 double Edit::frame_w()
365 {
366         return track->from_units(1) *
367                 edl->session->sample_rate /
368                 edl->local_session->zoom_sample;
369 }
370
371 double Edit::picon_w()
372 {
373         int w = 0, h = 0;
374         if(asset) {
375                 w = asset->width;
376                 h = asset->height;
377         }
378         else if(nested_edl) {
379                 w = nested_edl->session->output_w;
380                 h = nested_edl->session->output_h;
381         }
382         return w>0 && h>0 ? ((double)edl->local_session->zoom_track*w)/h : 0;
383 }
384
385 int Edit::picon_h()
386 {
387         return edl->local_session->zoom_track;
388 }
389
390
391 int Edit::dump(FILE *fp)
392 {
393         fprintf(fp,"     EDIT %p\n", this); fflush(fp);
394         fprintf(fp,"      nested_edl=%p %s asset=%p %s\n",
395                 nested_edl,
396                 nested_edl ? nested_edl->path : "",
397                 asset,
398                 asset ? asset->path : "");
399         fflush(fp);
400         fprintf(fp,"      channel %d, color %08x, group_id %d, is_selected %d\n",
401                 channel, color, group_id, is_selected);
402         if(transition)
403         {
404                 fprintf(fp,"      TRANSITION %p\n", transition);
405                 transition->dump(fp);
406         }
407         fprintf(fp,"      startsource %jd startproject %jd hard lt/rt %d/%d length %jd\n",
408                 startsource, startproject, hard_left, hard_right, length); fflush(fp);
409         return 0;
410 }
411
412 int Edit::load_properties(FileXML *file, int64_t &startproject)
413 {
414         startsource = file->tag.get_property("STARTSOURCE", (int64_t)0);
415         length = file->tag.get_property("LENGTH", (int64_t)0);
416         hard_left = file->tag.get_property("HARD_LEFT", (int64_t)0);
417         hard_right = file->tag.get_property("HARD_RIGHT", (int64_t)0);
418         color = file->tag.get_property("COLOR", 0);
419         group_id = file->tag.get_property("GROUP_ID", group_id);
420         user_title[0] = 0;
421         file->tag.get_property("USER_TITLE", user_title);
422         this->startproject = startproject;
423         load_properties_derived(file);
424         return 0;
425 }
426
427 void Edit::shift(int64_t difference)
428 {
429 //printf("Edit::shift 1 %p %jd %jd\n", this, startproject, difference);
430         startproject += difference;
431 //printf("Edit::shift 2 %jd %jd\n", startproject, difference);
432 }
433
434 int Edit::shift_start_in(int edit_mode,
435         int64_t newposition,
436         int64_t oldposition,
437         int edit_edits,
438         int edit_labels,
439         int edit_plugins,
440         int edit_autos,
441         Edits *trim_edits)
442 {
443         int64_t cut_length = newposition - oldposition;
444         int64_t end_previous_source, end_source;
445
446         if(edit_mode == MOVE_ALL_EDITS)
447         {
448                 if(cut_length < length)
449                 {        // clear partial
450                         edits->clear_recursive(oldposition,
451                                 newposition,
452                                 edit_edits,
453                                 edit_labels,
454                                 edit_plugins,
455                                 edit_autos,
456                                 trim_edits);
457                 }
458                 else
459                 {        // clear entire
460                         edits->clear_recursive(oldposition,
461                                 startproject + length,
462                                 edit_edits,
463                                 edit_labels,
464                                 edit_plugins,
465                                 edit_autos,
466                                 trim_edits);
467                 }
468         }
469         else
470         if(edit_mode == MOVE_ONE_EDIT)
471         {
472 // Paste silence and cut
473 //printf("Edit::shift_start_in 1\n");
474                 if(!previous)
475                 {
476                         Edit *new_edit = edits->create_edit();
477                         new_edit->startproject = this->startproject;
478                         new_edit->length = 0;
479                         edits->insert_before(this,
480                                 new_edit);
481                 }
482 //printf("Edit::shift_start_in 2 %p\n", previous);
483
484                 end_previous_source = previous->get_source_end(previous->startsource + previous->length + cut_length);
485                 if(end_previous_source > 0 &&
486                         previous->startsource + previous->length + cut_length > end_previous_source)
487                         cut_length = end_previous_source - previous->startsource - previous->length;
488
489                 if(cut_length < length)
490                 {               // Move in partial
491                         startproject += cut_length;
492                         startsource += cut_length;
493                         length -= cut_length;
494                         previous->length += cut_length;
495 //printf("Edit::shift_start_in 2\n");
496                 }
497                 else
498                 {               // Clear entire edit
499                         cut_length = length;
500                         previous->length += cut_length;
501                         for(Edit* current_edit = this; current_edit; current_edit = current_edit->next)
502                         {
503                                 current_edit->startproject += cut_length;
504                         }
505                         edits->clear_recursive(oldposition + cut_length,
506                                 startproject + cut_length,
507                                 edit_edits,
508                                 edit_labels,
509                                 edit_plugins,
510                                 edit_autos,
511                                 trim_edits);
512                 }
513 //printf("Edit::shift_start_in 3\n");
514         }
515         else
516         if(edit_mode == MOVE_NO_EDITS)
517         {
518                 end_source = get_source_end(startsource + length + cut_length);
519                 if(end_source > 0 && startsource + length + cut_length > end_source)
520                         cut_length = end_source - startsource - length;
521
522                 startsource += cut_length;
523         }
524         return 0;
525 }
526
527 int Edit::shift_start_out(int edit_mode,
528         int64_t newposition,
529         int64_t oldposition,
530         int edit_edits,
531         int edit_labels,
532         int edit_plugins,
533         int edit_autos,
534         Edits *trim_edits)
535 {
536         int64_t cut_length = oldposition - newposition;
537
538
539         if(asset || nested_edl)
540         {
541                 int64_t end_source = get_source_end(1);
542
543 //printf("Edit::shift_start_out 1 %jd %jd\n", startsource, cut_length);
544                 if(end_source > 0 && startsource < cut_length)
545                 {
546                         cut_length = startsource;
547                 }
548         }
549
550         if(edit_mode == MOVE_ALL_EDITS)
551         {
552 //printf("Edit::shift_start_out 10 %jd\n", cut_length);
553                 startsource -= cut_length;
554                 length += cut_length;
555
556                 if(edit_autos)
557                         edits->shift_keyframes_recursive(startproject,
558                                 cut_length);
559                 if(edit_plugins)
560                         edits->shift_effects_recursive(startproject,
561                                 cut_length,
562                                 edit_autos);
563
564                 for(Edit* current_edit = next; current_edit; current_edit = current_edit->next)
565                 {
566                         current_edit->startproject += cut_length;
567                 }
568         }
569         else
570         if(edit_mode == MOVE_ONE_EDIT)
571         {
572                 if(previous)
573                 {
574                         if(cut_length < previous->length)
575                         {   // Cut into previous edit
576                                 previous->length -= cut_length;
577                                 startproject -= cut_length;
578                                 startsource -= cut_length;
579                                 length += cut_length;
580                         }
581                         else
582                         {   // Clear entire previous edit
583                                 cut_length = previous->length;
584                                 previous->length = 0;
585                                 length += cut_length;
586                                 startsource -= cut_length;
587                                 startproject -= cut_length;
588                         }
589                 }
590         }
591         else
592         if(edit_mode == MOVE_NO_EDITS)
593         {
594                 startsource -= cut_length;
595         }
596
597 // Fix infinite length files
598         if(startsource < 0) startsource = 0;
599         return 0;
600 }
601
602 int Edit::shift_end_in(int edit_mode,
603         int64_t newposition,
604         int64_t oldposition,
605         int edit_edits,
606         int edit_labels,
607         int edit_plugins,
608         int edit_autos,
609         Edits *trim_edits)
610 {
611         int64_t cut_length = oldposition - newposition;
612
613         if(edit_mode == MOVE_ALL_EDITS)
614         {
615 //printf("Edit::shift_end_in 1\n");
616                 if(newposition > startproject)
617                 {        // clear partial edit
618 //printf("Edit::shift_end_in %p %p\n", track->edits, edits);
619                         edits->clear_recursive(newposition,
620                                 oldposition,
621                                 edit_edits,
622                                 edit_labels,
623                                 edit_plugins,
624                                 edit_autos,
625                                 trim_edits);
626                 }
627                 else
628                 {        // clear entire edit
629                         edits->clear_recursive(startproject,
630                                 oldposition,
631                                 edit_edits,
632                                 edit_labels,
633                                 edit_plugins,
634                                 edit_autos,
635                                 trim_edits);
636                 }
637         }
638         else
639         if(edit_mode == MOVE_ONE_EDIT)
640         {
641                 if(next)
642                 {
643                         if(next->asset)
644                         {
645                                 int64_t end_source = next->get_source_end(1);
646
647                                 if(end_source > 0 && next->startsource - cut_length < 0)
648                                 {
649                                         cut_length = next->startsource;
650                                 }
651                         }
652
653                         if(cut_length < length)
654                         {
655                                 length -= cut_length;
656                                 next->startproject -= cut_length;
657                                 next->startsource -= cut_length;
658                                 next->length += cut_length;
659 //printf("Edit::shift_end_in 2 %d\n", cut_length);
660                         }
661                         else
662                         {
663                                 cut_length = length;
664                                 next->length += cut_length;
665                                 next->startsource -= cut_length;
666                                 next->startproject -= cut_length;
667                                 length -= cut_length;
668                         }
669                 }
670                 else
671                 {
672                         if(cut_length < length)
673                         {
674                                 length -= cut_length;
675                         }
676                         else
677                         {
678                                 cut_length = length;
679                                 edits->clear_recursive(startproject,
680                                         oldposition,
681                                         edit_edits,
682                                         edit_labels,
683                                         edit_plugins,
684                                         edit_autos,
685                                         trim_edits);
686                         }
687                 }
688         }
689         else
690 // Does nothing for plugins
691         if(edit_mode == MOVE_NO_EDITS)
692         {
693 //printf("Edit::shift_end_in 3\n");
694                 int64_t end_source = get_source_end(1);
695                 if(end_source > 0 && startsource < cut_length)
696                 {
697                         cut_length = startsource;
698                 }
699                 startsource -= cut_length;
700         }
701         return 0;
702 }
703
704 int Edit::shift_end_out(int edit_mode,
705         int64_t newposition,
706         int64_t oldposition,
707         int edit_edits,
708         int edit_labels,
709         int edit_plugins,
710         int edit_autos,
711         Edits *trim_edits)
712 {
713         int64_t cut_length = newposition - oldposition;
714         int64_t endsource = get_source_end(startsource + length + cut_length);
715
716 // check end of edit against end of source file
717         if(endsource > 0 && startsource + length + cut_length > endsource)
718                 cut_length = endsource - startsource - length;
719
720 //printf("Edit::shift_end_out 1 %jd %d %d %d\n", oldposition, newposition, this->length, cut_length);
721         if(edit_mode == MOVE_ALL_EDITS)
722         {
723 // Extend length
724                 this->length += cut_length;
725
726 // Effects are shifted in length extension
727                 if(edit_plugins)
728                         edits->shift_effects_recursive(oldposition /* startproject */,
729                                 cut_length,
730                                 edit_autos);
731                 if(edit_autos)
732                         edits->shift_keyframes_recursive(oldposition /* startproject */,
733                                 cut_length);
734
735                 for(Edit* current_edit = next; current_edit; current_edit = current_edit->next)
736                 {
737                         current_edit->startproject += cut_length;
738                 }
739         }
740         else
741         if(edit_mode == MOVE_ONE_EDIT)
742         {
743                 if(next)
744                 {
745                         if(cut_length < next->length)
746                         {
747                                 length += cut_length;
748                                 next->startproject += cut_length;
749                                 next->startsource += cut_length;
750                                 next->length -= cut_length;
751 //printf("Edit::shift_end_out %d cut_length=%d\n", __LINE__, cut_length);
752                         }
753                         else
754                         {
755 //printf("Edit::shift_end_out %d cut_length=%d next->length=%d\n", __LINE__, cut_length, next->length);
756                                 cut_length = next->length;
757                                 next->startproject += next->length;
758                                 next->startsource += next->length;
759                                 next->length = 0;
760                                 length += cut_length;
761 //track->dump();
762                         }
763                 }
764                 else
765                 {
766                         length += cut_length;
767                 }
768         }
769         else
770         if(edit_mode == MOVE_NO_EDITS)
771         {
772                 startsource += cut_length;
773         }
774         return 0;
775 }
776
777 int Edit::popup_transition(float view_start, float zoom_units, int cursor_x, int cursor_y)
778 {
779         int64_t left, right, left_unit, right_unit;
780         if(!transition) return 0;
781         get_handle_parameters(left, right, left_unit, right_unit, view_start, zoom_units);
782
783         if(cursor_x > left && cursor_x < right)
784         {
785 //              transition->popup_transition(cursor_x, cursor_y);
786                 return 1;
787         }
788         return 0;
789 }
790
791 int Edit::select_handle(float view_start, float zoom_units, int cursor_x, int cursor_y, int64_t &selection)
792 {
793         int64_t left, right, left_unit, right_unit;
794         get_handle_parameters(left, right, left_unit, right_unit, view_start, zoom_units);
795
796         int64_t pixel1, pixel2;
797         pixel1 = left;
798         pixel2 = pixel1 + 10;
799
800 // test left edit
801 // cursor_x is faked in acanvas
802         if(cursor_x >= pixel1 && cursor_x <= pixel2)
803         {
804                 selection = left_unit;
805                 return 1;     // left handle
806         }
807
808         //int64_t endproject = startproject + length;
809         pixel2 = right;
810         pixel1 = pixel2 - 10;
811
812 // test right edit
813         if(cursor_x >= pixel1 && cursor_x <= pixel2)
814         {
815                 selection = right_unit;
816                 return 2;     // right handle
817         }
818         return 0;
819 }
820
821 void Edit::get_title(char *title)
822 {
823         if( user_title[0] ) {
824                 strcpy(title, user_title);
825                 return;
826         }
827         Indexable *idxbl = asset ? (Indexable*)asset : (Indexable*)nested_edl;
828         if( !idxbl ) {
829                 title[0] = 0;
830                 return;
831         }
832         FileSystem fs;
833         fs.extract_name(title, idxbl->path);
834         if( asset || track->data_type == TRACK_AUDIO ) {
835                 char number[BCSTRLEN];
836                 sprintf(number, " #%d", channel + 1);
837                 strcat(title, number);
838         }
839 }
840