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