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