improve ffmpeg format selection popup menu, more ffmpeg audio fixes
[goodguy/history.git] / cinelerra-5.0 / cinelerra / labels.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 "clip.h"
23 #include "edl.h"
24 #include "edlsession.h"
25 #include "filexml.h"
26 #include "labels.h"
27 #include "mwindow.h"
28 #include "mwindowgui.h"
29 #include "patchbay.h"
30 #include "recordlabel.h"
31 #include "mainsession.h"
32 #include "theme.h"
33 #include "timebar.h"
34 #include <string.h>
35
36
37
38 Labels::Labels(EDL *edl, const char *xml_tag)
39  : List<Label>()
40 {
41         this->edl = edl;
42         this->xml_tag = (char*)xml_tag;
43 }
44
45 Labels::~Labels()
46 {
47         delete_all();
48 }
49
50 void Labels::dump(FILE *fp)
51 {
52         for(Label *current = first; current; current = NEXT)
53         {
54                 fprintf(fp,"  label: %f\n", current->position);
55         }
56 }
57
58 void Labels::insert_labels(Labels *labels, double start, double length, int paste_silence)
59 {
60         Label *new_label;
61         Label *old_label;
62
63
64 //printf("Labels::insert_labels 1 %d %d\n", __LINE__, paste_silence);
65
66 // Insert silence in old labels
67         if(paste_silence)
68         {
69                 for(old_label = first; old_label; old_label = old_label->next)
70                 {
71                         if(old_label->position > start ||
72                                 edl->equivalent(old_label->position, start))
73                                 old_label->position += length;
74                 }
75         }
76
77
78 // Insert one new label at a time
79         for(new_label = labels->first; new_label; new_label = new_label->next)
80         {
81                 int exists = 0;
82 //printf("Labels::insert_labels 2 %f\n", new_label->position + start);
83
84 // Check every old label for existence
85                 for(old_label = first; old_label; old_label = old_label->next)
86                 {
87                         if(edl->equivalent(old_label->position, new_label->position + start))
88                         {
89                                 exists = 1;
90                                 break;
91                         }
92                         else
93                         if(old_label->position > new_label->position + start)
94                                 break;
95                 }
96
97                 if(!exists)
98                 {
99                         if(old_label)
100                                 insert_before(old_label, new Label(edl, this, new_label->position + start));
101                         else
102                                 append(new Label(edl, this, new_label->position + start));
103                 }
104         }
105 }
106
107
108 void Labels::insert_label(double position)
109 {
110         int exists = 0;
111         Label *old_label = 0;
112
113 // Check every old label for existence
114         for(old_label = first; old_label; old_label = old_label->next)
115         {
116                 if(edl->equivalent(old_label->position, position))
117                 {
118                         exists = 1;
119                         break;
120                 }
121                 else
122                 if(old_label->position > position)
123                         break;
124         }
125
126         if(!exists)
127         {
128                 if(old_label)
129                         insert_before(old_label, new Label(edl, this, position));
130                 else
131                         append(new Label(edl, this, position));
132         }
133 }
134
135
136 int Labels::toggle_label(double start, double end)
137 {
138         Label *current;
139 //printf("Labels::toggle_label 1 %f %f\n", start, end);
140
141 // handle selection start
142 // find label the selectionstart is after
143         for(current = first; 
144                 current && current->position < start && !edl->equivalent(current->position, start); 
145                 current = NEXT)
146         {
147 //printf("Labels::toggle_label 2 %f %f %f\n", start, end, current->position);
148                 ;
149         }
150
151         if(current)
152         {
153 //printf("Labels::toggle_label 3 %f %f %f\n", start, end, current->position);
154                 if(edl->equivalent(current->position, start))
155                 {        // remove it
156 //printf("Labels::toggle_label 1\n");
157                         remove(current);
158                 }
159                 else
160                 {        // insert before it
161                         current = insert_before(current, new Label(edl, this, start));
162                 }
163         }
164         else
165         {           // insert after last
166 //printf("Labels::toggle_label 1\n");
167                 current = append(new Label(edl, this, start));
168         }
169
170 // handle selection end
171         if(!EQUIV(start, end))
172         {
173 //printf("Labels::toggle_label 2 %.16e %.16e\n", start, end);
174 // find label the selectionend is after
175                 for(current = first; 
176                         current && current->position < end && !edl->equivalent(current->position, end); 
177                         current = NEXT)
178                 {
179                         ;
180                 }
181
182                 if(current)
183                 {
184                         if(edl->equivalent(current->position, end))
185                         {
186                                 remove(current);
187                         }
188                         else
189                         {
190                                 current = insert_before(current, new Label(edl, this, end));
191                         }
192                 }
193                 else
194                 {
195                         current = append(new Label(edl, this, end));
196                 }
197         }
198         return 0;
199 }
200
201 Label *Labels::add_label(double position)
202 {
203         Label *current;
204         for(current = first;
205                 current && current->position < position;
206                 current = NEXT)
207         {
208                 if( edl->equivalent(current->position, position) ) return 0; 
209         }
210
211         if(current)
212         {
213                 current = insert_before(current, new Label(edl, this, position));
214         }
215         else
216         {
217                 current = append(new Label(edl, this, position));
218         }
219         return current;
220 }
221
222 int Labels::delete_all()
223 {
224         while(last)
225                 remove(last);
226         return 0;
227 }
228
229 int Labels::copy(double start, double end, FileXML *xml)
230 {
231         char string[BCTEXTLEN];
232         xml->tag.set_title(xml_tag);
233         xml->append_tag();
234         xml->append_newline();
235
236         Label *current;
237         strcpy(string, xml_tag);
238         string[strlen(string) - 1] = 0;
239         for(current = label_of(start); 
240                 current && current->position <= end; 
241                 current = NEXT)
242         {
243                 xml->tag.set_title(string);
244                 xml->tag.set_property("TIME", (double)current->position - start);
245 //printf("Labels::copy %f\n", current->position - start);
246                 xml->append_tag();
247         }
248         
249         sprintf(string, "/%s", xml_tag);
250         xml->tag.set_title(string);
251         xml->append_tag();
252         xml->append_newline();
253         xml->append_newline();
254         return 0;
255 }
256
257 int Labels::copy_length(long start, long end) // return number of Labels in selection
258 {
259         int result = 0;
260         Label *current;
261         
262         for(current = label_of(start); current && current->position <= end; current = NEXT)
263         {
264                 result++;
265         }
266         return result;
267 }
268
269 void Labels::copy_from(Labels *labels)
270 {
271         while(last) delete last;
272
273         for(Label *current = labels->first; current; current = NEXT)
274         {
275                 append(new Label(edl, this, current->position));
276         }
277 }
278
279
280 Labels& Labels::operator=(Labels &that)
281 {
282         copy_from(&that);
283 printf("Labels::operator= 1\n");
284         return *this;
285 }
286
287
288 int Labels::save(FileXML *xml)
289 {
290         xml->tag.set_title("LABELS");
291         xml->append_tag();
292         xml->append_newline();
293
294         Label *current;
295
296         for(current = first; current; current = NEXT)
297         {
298                 xml->tag.set_title("LABEL");
299                 xml->tag.set_property("TIME", (double)current->position);
300                 xml->append_tag();
301         }
302         
303         xml->append_newline();
304         xml->tag.set_title("/LABELS");
305         xml->append_tag();
306         xml->append_newline();
307         xml->append_newline();
308         return 0;
309 }
310
311 int Labels::load(FileXML *xml, uint32_t load_flags)
312 {
313         int result = 0;
314         char string1[BCTEXTLEN], string2[BCTEXTLEN];
315
316         sprintf(string1, "/%s", xml_tag);
317         strcpy(string2, xml_tag);
318         string2[strlen(string2) - 1] = 0;
319
320         do{
321                 result = xml->read_tag();
322                 if(!result)
323                 {
324                         if(xml->tag.title_is(string1))
325                         {
326                                 result = 1;
327                         }
328                         else
329                         if(xml->tag.title_is(string2))
330                         {
331                                 double position = xml->tag.get_property("TIME", (double)-1);
332                                 if(position < 0)
333                                         position = xml->tag.get_property("SAMPLE", (double)-1);
334 //printf("Labels::load %f\n", position);
335                                 if(position > -1)
336                                 {
337                                         Label *current = label_of(position);
338                                         current = insert_before(current, new Label(edl, this, position));
339                                 }
340                         }
341                         else
342                         if(xml->tag.title_is("INPOINT"))
343                         {
344                                 double position = xml->tag.get_property("TIME", (double)-1);
345                                 if(position < 0)
346                                         position = xml->tag.get_property("SAMPLE", (double)-1);
347                                 if(position > -1)
348                                 {
349                                         ;
350                                 }
351                         }
352                         else
353                         if(xml->tag.title_is("OUTPOINT"))
354                         {
355                                 double position = xml->tag.get_property("TIME", (double)-1);
356                                 if(position < 0)
357                                         position = xml->tag.get_property("SAMPLE", (double)-1);
358                                 if(position > -1)
359                                 {
360                                         ;
361                                 }
362                         }
363                 }
364         }while(!result);
365         return 0;
366 }
367
368
369
370 int Labels::clear(double start, double end, int follow)
371 {
372         Label *current;
373         Label *next;
374
375 //printf("Labels::clear 1\n");
376         current = label_of(start);
377 //printf("Labels::clear 2\n");
378
379 // remove selected labels
380         while(current && current->position < end)
381         {
382                 next = NEXT;
383                 delete current;              
384                 current = next;
385         }
386
387 // Shift later labels
388         if(follow)
389         {
390                 while(current)
391                 {
392 //printf("Labels::clear %d %f %f\n", __LINE__, current->position, end - start);
393                         current->position -= end - start;   // shift labels forward
394 //printf("Labels::clear %d %f %f\n", __LINE__, current->position, end - start);
395                         current = NEXT;
396                 }
397 //printf("Labels::clear 4\n");
398                 optimize();
399 //printf("Labels::clear 5\n");
400         }
401
402         return 0;
403 }
404
405
406 Label* Labels::prev_label(double position)
407 {
408         Label *current;
409
410 // Test for label under cursor position
411         for(current = first; 
412                 current && !edl->equivalent(current->position, position); 
413                 current = NEXT)
414                 ;
415
416 // Test for label after cursor position
417         if(!current)
418                 for(current = first;
419                         current && current->position < position;
420                         current = NEXT)
421                         ;
422
423 // Test for label before cursor position
424         if(!current) 
425                 current = last;
426         else
427 // Get previous label
428                 current = PREVIOUS;
429
430         return current;
431 }
432
433 Label* Labels::next_label(double position)
434 {
435         Label *current;
436
437 // Test for label under cursor position
438         for(current = first; 
439                 current && !edl->equivalent(current->position, position); 
440                 current = NEXT)
441                 ;
442
443 // Test for label before cursor position
444         if(!current)
445                 for(current = last;
446                         current && current->position > position;
447                         current = PREVIOUS)
448                         ;
449
450 // Test for label after cursor position
451         if(!current)
452                 current = first;
453         else
454 // Get next label
455                 current = NEXT;
456
457         return current;
458 }
459
460 int Labels::insert(double start, double length)
461 {
462 // shift every label including the first one back
463         Label *current;
464
465 //printf("Labels::insert %d\n", __LINE__);
466         for(current = label_of(start); current; current = NEXT)
467         {
468                 current->position += length;
469         }
470         return 0;
471 }
472
473 int Labels::paste_silence(double start, double end)
474 {
475         insert(start, end - start);
476         optimize();
477         return 0;
478 }
479
480 int Labels::modify_handles(double oldposition, 
481         double newposition, 
482         int currentend, 
483         int handle_mode,
484         int edit_labels)
485 {
486         if(edit_labels &&
487                 handle_mode == MOVE_ALL_EDITS)
488         {
489                 if(currentend == 0)          // left handle
490                 {
491                         if(newposition < oldposition)
492                         {
493                                 insert(oldposition, oldposition - newposition);    // shift all labels right
494                         }
495                         else
496                         {
497                                 clear(oldposition, newposition);   // clear selection
498                         }
499                 }
500                 else
501                 {                            // right handle
502                         if(newposition < oldposition)
503                         {
504                                 clear(newposition, oldposition);
505                         }
506                         else
507                         {
508                                 insert(oldposition, newposition - oldposition);
509                         }
510                 }
511         }
512         return 0;
513 }
514
515 int Labels::optimize()
516 {
517         int result = 1;
518         Label *current;
519
520         while(result)
521         {
522                 result = 0;
523                 
524                 for(current = first; current && NEXT && !result;)
525                 {
526                         Label *next = NEXT;
527                         if(current->position == next->position)
528                         {
529                                 delete current;
530                                 result  = 1;
531                         }
532                         current = next;
533                 }
534         }
535         return 0;
536 }
537
538 Label* Labels::label_of(double position)
539 {
540         Label *current;
541
542         for(current = first; current; current = NEXT)
543         {
544                 if(current->position >= position) return current;
545         }
546         return 0;
547 }
548
549
550
551
552
553
554
555
556
557
558 Label::Label()
559  : ListItem<Label>()
560 {
561 }
562
563 Label::Label(EDL *edl, Labels *labels, double position)
564  : ListItem<Label>()
565 {
566         this->edl = edl;
567         this->labels = labels;
568         this->position = position;
569 }
570
571
572 Label::~Label()
573 {
574 //      if(toggle) delete toggle;
575 }
576
577 LabelToggle::LabelToggle(MWindow *mwindow, 
578         Label *label, 
579         int x, 
580         int y, 
581         long position)
582  : BC_Label(x, y, 0)
583 {
584         this->mwindow = mwindow;
585         this->label = label;
586 }
587
588 LabelToggle::~LabelToggle() { }
589
590 int LabelToggle::handle_event()
591 {
592         return 0;
593 }
594