initial commit
[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 "stringfile.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 = (char*)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\n", current->position);
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 %d %d\n", __LINE__, paste_silence);
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));
102                         else
103                                 append(new Label(edl, this, new_label->position + start));
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         char string[BCTEXTLEN];
233         xml->tag.set_title(xml_tag);
234         xml->append_tag();
235         xml->append_newline();
236
237         Label *current;
238         strcpy(string, xml_tag);
239         string[strlen(string) - 1] = 0;
240         for(current = label_of(start); 
241                 current && current->position <= end; 
242                 current = NEXT)
243         {
244                 xml->tag.set_title(string);
245                 xml->tag.set_property("TIME", (double)current->position - start);
246 //printf("Labels::copy %f\n", current->position - start);
247                 xml->append_tag();
248         }
249         
250         sprintf(string, "/%s", xml_tag);
251         xml->tag.set_title(string);
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                 append(new Label(edl, this, current->position));
277         }
278 }
279
280
281 Labels& Labels::operator=(Labels &that)
282 {
283         copy_from(&that);
284 printf("Labels::operator= 1\n");
285         return *this;
286 }
287
288
289 int Labels::save(FileXML *xml)
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->append_tag();
302         }
303         
304         xml->append_newline();
305         xml->tag.set_title("/LABELS");
306         xml->append_tag();
307         xml->append_newline();
308         xml->append_newline();
309         return 0;
310 }
311
312 int Labels::load(FileXML *xml, uint32_t load_flags)
313 {
314         int result = 0;
315         char string1[BCTEXTLEN], string2[BCTEXTLEN];
316
317         sprintf(string1, "/%s", xml_tag);
318         strcpy(string2, xml_tag);
319         string2[strlen(string2) - 1] = 0;
320
321         do{
322                 result = xml->read_tag();
323                 if(!result)
324                 {
325                         if(xml->tag.title_is(string1))
326                         {
327                                 result = 1;
328                         }
329                         else
330                         if(xml->tag.title_is(string2))
331                         {
332                                 double position = xml->tag.get_property("TIME", (double)-1);
333                                 if(position < 0)
334                                         position = xml->tag.get_property("SAMPLE", (double)-1);
335 //printf("Labels::load %f\n", position);
336                                 if(position > -1)
337                                 {
338                                         Label *current = label_of(position);
339                                         current = insert_before(current, new Label(edl, this, position));
340                                 }
341                         }
342                         else
343                         if(xml->tag.title_is("INPOINT"))
344                         {
345                                 double position = xml->tag.get_property("TIME", (double)-1);
346                                 if(position < 0)
347                                         position = xml->tag.get_property("SAMPLE", (double)-1);
348                                 if(position > -1)
349                                 {
350                                         ;
351                                 }
352                         }
353                         else
354                         if(xml->tag.title_is("OUTPOINT"))
355                         {
356                                 double position = xml->tag.get_property("TIME", (double)-1);
357                                 if(position < 0)
358                                         position = xml->tag.get_property("SAMPLE", (double)-1);
359                                 if(position > -1)
360                                 {
361                                         ;
362                                 }
363                         }
364                 }
365         }while(!result);
366         return 0;
367 }
368
369
370
371 int Labels::clear(double start, double end, int follow)
372 {
373         Label *current;
374         Label *next;
375
376 //printf("Labels::clear 1\n");
377         current = label_of(start);
378 //printf("Labels::clear 2\n");
379
380 // remove selected labels
381         while(current && current->position < end)
382         {
383                 next = NEXT;
384                 delete current;              
385                 current = next;
386         }
387
388 // Shift later labels
389         if(follow)
390         {
391                 while(current)
392                 {
393 //printf("Labels::clear %d %f %f\n", __LINE__, current->position, end - start);
394                         current->position -= end - start;   // shift labels forward
395 //printf("Labels::clear %d %f %f\n", __LINE__, current->position, end - start);
396                         current = NEXT;
397                 }
398 //printf("Labels::clear 4\n");
399                 optimize();
400 //printf("Labels::clear 5\n");
401         }
402
403         return 0;
404 }
405
406
407 Label* Labels::prev_label(double position)
408 {
409         Label *current;
410
411 // Test for label under cursor position
412         for(current = first; 
413                 current && !edl->equivalent(current->position, position); 
414                 current = NEXT)
415                 ;
416
417 // Test for label after cursor position
418         if(!current)
419                 for(current = first;
420                         current && current->position < position;
421                         current = NEXT)
422                         ;
423
424 // Test for label before cursor position
425         if(!current) 
426                 current = last;
427         else
428 // Get previous label
429                 current = PREVIOUS;
430
431         return current;
432 }
433
434 Label* Labels::next_label(double position)
435 {
436         Label *current;
437
438 // Test for label under cursor position
439         for(current = first; 
440                 current && !edl->equivalent(current->position, position); 
441                 current = NEXT)
442                 ;
443
444 // Test for label before cursor position
445         if(!current)
446                 for(current = last;
447                         current && current->position > position;
448                         current = PREVIOUS)
449                         ;
450
451 // Test for label after cursor position
452         if(!current)
453                 current = first;
454         else
455 // Get next label
456                 current = NEXT;
457
458         return current;
459 }
460
461 int Labels::insert(double start, double length)
462 {
463 // shift every label including the first one back
464         Label *current;
465
466 //printf("Labels::insert %d\n", __LINE__);
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)
565  : ListItem<Label>()
566 {
567         this->edl = edl;
568         this->labels = labels;
569         this->position = position;
570 }
571
572
573 Label::~Label()
574 {
575 //      if(toggle) delete toggle;
576 }
577
578 LabelToggle::LabelToggle(MWindow *mwindow, 
579         Label *label, 
580         int x, 
581         int y, 
582         long position)
583  : BC_Label(x, y, 0)
584 {
585         this->mwindow = mwindow;
586         this->label = label;
587 }
588
589 LabelToggle::~LabelToggle() { }
590
591 int LabelToggle::handle_event()
592 {
593         return 0;
594 }
595