build version update
[goodguy/history.git] / cinelerra-5.1 / 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 = 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 '%s'\n", current->position, current->textstr);
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 %f\n", start);
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, new_label->textstr));
101                         else
102                                 append(new Label(edl, this, new_label->position + start, new_label->textstr));
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         xml->tag.set_title("LABELS");
232         xml->append_tag();
233         xml->append_newline();
234
235         Label *current;
236         for(current = label_of(start);
237                 current && current->position <= end;
238                 current = NEXT)
239         {
240                 xml->tag.set_title("LABEL");
241                 xml->tag.set_property("TIME", (double)current->position - start);
242                 xml->tag.set_property("TEXTSTR", current->textstr);
243 //printf("Labels::copy %f\n", current->position - start);
244                 xml->append_tag();
245                 xml->tag.set_title("/LABEL");
246                 xml->append_tag();
247                 xml->append_newline();
248         }
249
250         xml->tag.set_title("/LABELS");
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, current->textstr));
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 // Note: Normally the saving of Labels is done by Labels::copy()
290 {
291         xml->tag.set_title("LABELS");
292         xml->append_tag();
293         xml->append_newline();
294
295         Label *current;
296
297         for(current = first; current; current = NEXT)
298         {
299                 xml->tag.set_title("LABEL");
300                 xml->tag.set_property("TIME", (double)current->position);
301                 xml->tag.set_property("TEXTSTR", current->textstr);
302                 xml->append_tag();
303                 xml->tag.set_title("/LABEL");
304                 xml->append_tag();
305                 xml->append_newline();
306         }
307
308         xml->append_newline();
309         xml->tag.set_title("/LABELS");
310         xml->append_tag();
311         xml->append_newline();
312         xml->append_newline();
313         return 0;
314 }
315
316 int Labels::load(FileXML *xml, uint32_t load_flags)
317 {
318         int result = 0;
319         char string1[BCTEXTLEN], string2[BCTEXTLEN];
320
321         sprintf(string1, "/%s", xml_tag);
322         strcpy(string2, xml_tag);
323         string2[strlen(string2) - 1] = 0;
324
325         do{
326                 result = xml->read_tag();
327                 if(!result)
328                 {
329                         if(xml->tag.title_is(string1))
330                         {
331                                 result = 1;
332                         }
333                         else
334                         if(xml->tag.title_is(string2))
335                         {
336                                 double position = xml->tag.get_property("TIME", (double)-1);
337                                 if(position < 0)
338                                         position = xml->tag.get_property("SAMPLE", (double)-1);
339 //printf("Labels::load %f\n", position);
340                                 if(position > -1)
341                                 {
342                                         Label *current = label_of(position);
343                                         current = insert_before(current, new Label(edl, this, position, ""));
344                                         xml->tag.get_property("TEXTSTR", current->textstr);
345                                 }
346                         }
347                         else
348                         if(xml->tag.title_is("INPOINT"))
349                         {
350                                 double position = xml->tag.get_property("TIME", (double)-1);
351                                 if(position < 0)
352                                         position = xml->tag.get_property("SAMPLE", (double)-1);
353                                 if(position > -1)
354                                 {
355                                         ;
356                                 }
357                         }
358                         else
359                         if(xml->tag.title_is("OUTPOINT"))
360                         {
361                                 double position = xml->tag.get_property("TIME", (double)-1);
362                                 if(position < 0)
363                                         position = xml->tag.get_property("SAMPLE", (double)-1);
364                                 if(position > -1)
365                                 {
366                                         ;
367                                 }
368                         }
369                 }
370         }while(!result);
371         return 0;
372 }
373
374
375
376 int Labels::clear(double start, double end, int follow)
377 {
378         Label *current;
379         Label *next;
380
381 //printf("Labels::clear 1\n");
382         current = label_of(start);
383 //printf("Labels::clear 2\n");
384 // remove selected labels
385         while(current && current->position < end)
386         {
387                 next = NEXT;
388                 delete current;
389                 current = next;
390         }
391 // Shift later labels
392 //printf("Labels::clear 3\n");
393         if(follow)
394         {
395                 while(current)
396                 {
397                         current->position -= end - start;   // shift labels forward
398                         current = NEXT;
399                 }
400 //printf("Labels::clear 4\n");
401                 optimize();
402 //printf("Labels::clear 5\n");
403         }
404
405         return 0;
406 }
407
408
409 Label* Labels::prev_label(double position)
410 {
411         Label *current;
412
413 // Test for label under cursor position
414         for(current = first;
415                 current && !edl->equivalent(current->position, position);
416                 current = NEXT)
417                 ;
418
419 // Test for label after cursor position
420         if(!current)
421                 for(current = first;
422                         current && current->position < position;
423                         current = NEXT)
424                         ;
425
426 // Test for label before cursor position
427         if(!current)
428                 current = last;
429         else
430 // Get previous label
431                 current = PREVIOUS;
432
433         return current;
434 }
435
436 Label* Labels::next_label(double position)
437 {
438         Label *current;
439
440 // Test for label under cursor position
441         for(current = first;
442                 current && !edl->equivalent(current->position, position);
443                 current = NEXT)
444                 ;
445
446 // Test for label before cursor position
447         if(!current)
448                 for(current = last;
449                         current && current->position > position;
450                         current = PREVIOUS)
451                         ;
452
453 // Test for label after cursor position
454         if(!current)
455                 current = first;
456         else
457 // Get next label
458                 current = NEXT;
459
460         return current;
461 }
462
463 int Labels::insert(double start, double length)
464 {      // shift every label including the first one back
465         Label *current;
466
467         for(current = label_of(start); current; current = NEXT)
468         {
469                 current->position += length;
470         }
471         return 0;
472 }
473
474 int Labels::paste_silence(double start, double end)
475 {
476         insert(start, end - start);
477         optimize();
478         return 0;
479 }
480
481 int Labels::modify_handles(double oldposition,
482         double newposition,
483         int currentend,
484         int handle_mode,
485         int edit_labels)
486 {
487         if(edit_labels &&
488                 handle_mode == MOVE_ALL_EDITS)
489         {
490                 if(currentend == 0)          // left handle
491                 {
492                         if(newposition < oldposition)
493                         {
494                                 insert(oldposition, oldposition - newposition);    // shift all labels right
495                         }
496                         else
497                         {
498                                 clear(oldposition, newposition);   // clear selection
499                         }
500                 }
501                 else
502                 {                            // right handle
503                         if(newposition < oldposition)
504                         {
505                                 clear(newposition, oldposition);
506                         }
507                         else
508                         {
509                                 insert(oldposition, newposition - oldposition);
510                         }
511                 }
512         }
513         return 0;
514 }
515
516 int Labels::optimize()
517 {
518         int result = 1;
519         Label *current;
520
521         while(result)
522         {
523                 result = 0;
524
525                 for(current = first; current && NEXT && !result;)
526                 {
527                         Label *next = NEXT;
528                         if(current->position == next->position)
529                         {
530                                 delete current;
531                                 result  = 1;
532                         }
533                         current = next;
534                 }
535         }
536         return 0;
537 }
538
539 Label* Labels::label_of(double position)
540 {
541         Label *current;
542
543         for(current = first; current; current = NEXT)
544         {
545                 if(current->position >= position) return current;
546         }
547         return 0;
548 }
549
550
551
552
553
554
555
556
557
558
559 Label::Label()
560  : ListItem<Label>()
561 {
562 }
563
564 Label::Label(EDL *edl, Labels *labels, double position, const char *textstr)
565  : ListItem<Label>()
566 {
567         this->edl = edl;
568         this->labels = labels;
569         this->position = position;
570         strcpy(this->textstr, textstr ? textstr : "");
571 }
572
573
574 Label::~Label()
575 {
576 //      if(toggle) delete toggle;
577 }
578
579 LabelToggle::LabelToggle(MWindow *mwindow,
580         Label *label,
581         int x,
582         int y,
583         long position)
584  : BC_Label(x, y, 0)
585 {
586         this->mwindow = mwindow;
587         this->label = label;
588 }
589
590 LabelToggle::~LabelToggle() { }
591
592 int LabelToggle::handle_event()
593 {
594         return 0;
595 }
596