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