r1026: Videoscope layout tweaks.
[cinelerra_cv/ct.git] / cinelerra / labels.C
blob10ccb5fc3be45d828a02372f4771dd56f63305a0
1 #include "clip.h"
2 #include "edl.h"
3 #include "edlsession.h"
4 #include "filexml.h"
5 #include "labels.h"
6 #include "mwindow.h"
7 #include "mwindowgui.h"
8 #include "patchbay.h"
9 #include "recordlabel.h"
10 #include "mainsession.h"
11 #include "stringfile.h"
12 #include "theme.h"
13 #include "timebar.h"
14 #include <string.h>
18 Labels::Labels(EDL *edl, char *xml_tag)
19  : List<Label>()
21         this->edl = edl;
22         this->xml_tag = xml_tag;
25 Labels::~Labels()
27         delete_all();
30 void Labels::dump()
32         for(Label *current = first; current; current = NEXT)
33         {
34                 printf("  label: %f '%s'\n", current->position, current->textstr);
35         }
38 void Labels::insert_labels(Labels *labels, double start, double length, int paste_silence)
40         Label *new_label;
41         Label *old_label;
44 //printf("Labels::insert_labels 1 %f\n", start);
46 // Insert silence in old labels
47         if(paste_silence)
48         {
49                 for(old_label = first; old_label; old_label = old_label->next)
50                 {
51                         if(old_label->position > start ||
52                                 edl->equivalent(old_label->position, start))
53                                 old_label->position += length;
54                 }
55         }
58 // Insert one new label at a time
59         for(new_label = labels->first; new_label; new_label = new_label->next)
60         {
61                 int exists = 0;
62 //printf("Labels::insert_labels 2 %f\n", new_label->position + start);
64 // Check every old label for existence
65                 for(old_label = first; old_label; old_label = old_label->next)
66                 {
67                         if(edl->equivalent(old_label->position, new_label->position + start))
68                         {
69                                 exists = 1;
70                                 break;
71                         }
72                         else
73                         if(old_label->position > new_label->position + start)
74                                 break;
75                 }
77                 if(!exists)
78                 {
79                         if(old_label)
80                                 insert_before(old_label, new Label(edl, this, new_label->position + start, new_label->textstr));
81                         else
82                                 append(new Label(edl, this, new_label->position + start, new_label->textstr));
83                 }
84         }
87 int Labels::toggle_label(double start, double end)
89         Label *current;
90 //printf("Labels::toggle_label 1 %f %f\n", start, end);
92 // handle selection start
93 // find label the selectionstart is after
94         for(current = first; 
95                 current && current->position < start && !edl->equivalent(current->position, start); 
96                 current = NEXT)
97         {
98 //printf("Labels::toggle_label 2 %f %f %f\n", start, end, current->position);
99                 ;
100         }
102         if(current)
103         {
104 //printf("Labels::toggle_label 3 %f %f %f\n", start, end, current->position);
105                 if(edl->equivalent(current->position, start))
106                 {        // remove it
107 //printf("Labels::toggle_label 1\n");
108                         remove(current);
109                 }
110                 else
111                 {        // insert before it
112                         current = insert_before(current, new Label(edl, this, start, ""));
113                 }
114         }
115         else
116         {           // insert after last
117 //printf("Labels::toggle_label 1\n");
118                 current = append(new Label(edl, this, start, ""));
119         }
121 // handle selection end
122         if(!EQUIV(start, end))
123         {
124 //printf("Labels::toggle_label 2 %.16e %.16e\n", start, end);
125 // find label the selectionend is after
126                 for(current = first; 
127                         current && current->position < end && !edl->equivalent(current->position, end); 
128                         current = NEXT)
129                 {
130                         ;
131                 }
133                 if(current)
134                 {
135                         if(edl->equivalent(current->position, end))
136                         {
137                                 remove(current);
138                         }
139                         else
140                         {
141                                 current = insert_before(current, new Label(edl, this, end, ""));
142                         }
143                 }
144                 else
145                 {
146                         current = append(new Label(edl, this, end, ""));
147                 }
148         }
149         return 0;
152 int Labels::delete_all()
154         while(last)
155                 remove(last);
156         return 0;
159 int Labels::copy(double start, double end, FileXML *xml)
161         char string[BCTEXTLEN];
162         xml->tag.set_title(xml_tag);
163         xml->append_tag();
164         xml->append_newline();
166         Label *current;
167         sprintf(string, "/%s", xml_tag);
168         string[strlen(string) - 1] = 0; // remove trailing "S" on "LABELS" giving "LABEL"
169         for(current = label_of(start); 
170                 current && current->position <= end; 
171                 current = NEXT)
172         {
173                 xml->tag.set_title(string+1); // skip the "/" for opening tag
174                 xml->tag.set_property("TIME", (double)current->position - start);
175                 xml->tag.set_property("TEXTSTR", current->textstr);
176 //printf("Labels::copy %f\n", current->position - start);
177                 xml->append_tag();
178                 xml->tag.set_title(string); // closing tag
179                 xml->append_tag();
180                 xml->append_newline();
181         }
182         
183         sprintf(string, "/%s", xml_tag);
184         xml->tag.set_title(string);
185         xml->append_tag();
186         xml->append_newline();
187         xml->append_newline();
188         return 0;
191 int Labels::copy_length(long start, long end) // return number of Labels in selection
193         int result = 0;
194         Label *current;
195         
196         for(current = label_of(start); current && current->position <= end; current = NEXT)
197         {
198                 result++;
199         }
200         return result;
203 void Labels::copy_from(Labels *labels)
205         while(last) delete last;
207         for(Label *current = labels->first; current; current = NEXT)
208         {
209                 append(new Label(edl, this, current->position, current->textstr));
210         }
214 Labels& Labels::operator=(Labels &that)
216         copy_from(&that);
217 printf("Labels::operator= 1\n");
218         return *this;
222 int Labels::save(FileXML *xml)
223 // Note: Normally the saving of Labels is done by Labels::copy()
225         xml->tag.set_title("LABELS");
226         xml->append_tag();
227         xml->append_newline();
229         Label *current;
231         for(current = first; current; current = NEXT)
232         {
233                 xml->tag.set_title("LABEL");
234                 xml->tag.set_property("TIME", (double)current->position);
235                 xml->tag.set_property("TEXTSTR", current->textstr);
236                 xml->append_tag();
237                 xml->tag.set_title("/LABEL");
238                 xml->append_tag();
239                 xml->append_newline();
240         }
241         
242         xml->append_newline();
243         xml->tag.set_title("/LABELS");
244         xml->append_tag();
245         xml->append_newline();
246         xml->append_newline();
247         return 0;
250 int Labels::load(FileXML *xml, uint32_t load_flags)
252         int result = 0;
253         char string1[BCTEXTLEN], string2[BCTEXTLEN];
255         sprintf(string1, "/%s", xml_tag);
256         strcpy(string2, xml_tag);
257         string2[strlen(string2) - 1] = 0;
259         do{
260                 result = xml->read_tag();
261                 if(!result)
262                 {
263                         if(xml->tag.title_is(string1))
264                         {
265                                 result = 1;
266                         }
267                         else
268                         if(xml->tag.title_is(string2))
269                         {
270                                 double position = xml->tag.get_property("TIME", (double)-1);
271                                 if(position < 0)
272                                         position = xml->tag.get_property("SAMPLE", (double)-1);
273 //printf("Labels::load %f\n", position);
274                                 if(position > -1)
275                                 {
276                                         Label *current = label_of(position);
277                                         current = insert_before(current, new Label(edl, this, position, ""));
278                                         xml->tag.get_property("TEXTSTR", current->textstr);
279                                 }
280                         }
281                         else
282                         if(xml->tag.title_is("INPOINT"))
283                         {
284                                 double position = xml->tag.get_property("TIME", (double)-1);
285                                 if(position < 0)
286                                         position = xml->tag.get_property("SAMPLE", (double)-1);
287                                 if(position > -1)
288                                 {
289                                         ;
290                                 }
291                         }
292                         else
293                         if(xml->tag.title_is("OUTPOINT"))
294                         {
295                                 double position = xml->tag.get_property("TIME", (double)-1);
296                                 if(position < 0)
297                                         position = xml->tag.get_property("SAMPLE", (double)-1);
298                                 if(position > -1)
299                                 {
300                                         ;
301                                 }
302                         }
303                 }
304         }while(!result);
305         return 0;
310 int Labels::clear(double start, double end, int follow)
312         Label *current;
313         Label *next;
315 //printf("Labels::clear 1\n");
316         current = label_of(start);
317 //printf("Labels::clear 2\n");
318 // remove selected labels
319         while(current && current->position < end)
320         {
321                 next = NEXT;
322                 delete current;              
323                 current = next;
324         }
325 // Shift later labels
326 //printf("Labels::clear 3\n");
327         if(follow)
328         {
329                 while(current)
330                 {
331                         current->position -= end - start;   // shift labels forward
332                         current = NEXT;
333                 }
334 //printf("Labels::clear 4\n");
335                 optimize();
336 //printf("Labels::clear 5\n");
337         }
339         return 0;
343 Label* Labels::prev_label(double position)
345         Label *current;
347 // Test for label under cursor position
348         for(current = first; 
349                 current && !edl->equivalent(current->position, position); 
350                 current = NEXT)
351                 ;
353 // Test for label after cursor position
354         if(!current)
355                 for(current = first;
356                         current && current->position < position;
357                         current = NEXT)
358                         ;
360 // Test for label before cursor position
361         if(!current) 
362                 current = last;
363         else
364 // Get previous label
365                 current = PREVIOUS;
367         return current;
370 Label* Labels::next_label(double position)
372         Label *current;
374 // Test for label under cursor position
375         for(current = first; 
376                 current && !edl->equivalent(current->position, position); 
377                 current = NEXT)
378                 ;
380 // Test for label before cursor position
381         if(!current)
382                 for(current = last;
383                         current && current->position > position;
384                         current = PREVIOUS)
385                         ;
387 // Test for label after cursor position
388         if(!current)
389                 current = first;
390         else
391 // Get next label
392                 current = NEXT;
394         return current;
397 int Labels::insert(double start, double length)
398 {      // shift every label including the first one back
399         Label *current;
401         for(current = label_of(start); current; current = NEXT)
402         {
403                 current->position += length;
404         }
405         return 0;
408 int Labels::paste_silence(double start, double end)
410         insert(start, end - start);
411         optimize();
412         return 0;
415 int Labels::modify_handles(double oldposition, 
416         double newposition, 
417         int currentend, 
418         int handle_mode,
419         int edit_labels)
421         if(edit_labels &&
422                 handle_mode == MOVE_ALL_EDITS)
423         {
424                 if(currentend == 0)          // left handle
425                 {
426                         if(newposition < oldposition)
427                         {
428                                 insert(oldposition, oldposition - newposition);    // shift all labels right
429                         }
430                         else
431                         {
432                                 clear(oldposition, newposition);   // clear selection
433                         }
434                 }
435                 else
436                 {                            // right handle
437                         if(newposition < oldposition)
438                         {
439                                 clear(newposition, oldposition);
440                         }
441                         else
442                         {
443                                 insert(oldposition, newposition - oldposition);
444                         }
445                 }
446         }
447         return 0;
450 int Labels::optimize()
452         int result = 1;
453         Label *current;
455         while(result)
456         {
457                 result = 0;
458                 
459                 for(current = first; current && NEXT && !result;)
460                 {
461                         Label *next = NEXT;
462                         if(current->position == next->position)
463                         {
464                                 delete current;
465                                 result  = 1;
466                         }
467                         current = next;
468                 }
469         }
470         return 0;
473 Label* Labels::label_of(double position)
475         Label *current;
477         for(current = first; current; current = NEXT)
478         {
479                 if(current->position >= position) return current;
480         }
481         return 0;
493 Label::Label()
494  : ListItem<Label>()
498 Label::Label(EDL *edl, Labels *labels, double position, char *textstr = 0)
499  : ListItem<Label>()
501         this->edl = edl;
502         this->labels = labels;
503         this->position = position;
504         if (textstr)
505                 strcpy(this->textstr, textstr);
506         else
507                 strcpy(this->textstr, "");
511 Label::~Label()
513 //      if(toggle) delete toggle;
516 LabelToggle::LabelToggle(MWindow *mwindow, 
517         Label *label, 
518         int x, 
519         int y, 
520         long position)
521  : BC_Label(x, y, 0)
523         this->mwindow = mwindow;
524         this->label = label;
527 LabelToggle::~LabelToggle() { }
529 int LabelToggle::handle_event()
531         return 0;