Merge CV, ver=5.1; ops/methods from HV, and interface from CV where possible
[goodguy/history.git] / cinelerra-5.1 / cinelerra / labels.C
diff --git a/cinelerra-5.1/cinelerra/labels.C b/cinelerra-5.1/cinelerra/labels.C
new file mode 100644 (file)
index 0000000..933985e
--- /dev/null
@@ -0,0 +1,596 @@
+
+/*
+ * CINELERRA
+ * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "clip.h"
+#include "edl.h"
+#include "edlsession.h"
+#include "filexml.h"
+#include "labels.h"
+#include "mwindow.h"
+#include "mwindowgui.h"
+#include "patchbay.h"
+#include "recordlabel.h"
+#include "mainsession.h"
+#include "theme.h"
+#include "timebar.h"
+#include <string.h>
+
+
+
+Labels::Labels(EDL *edl, const char *xml_tag)
+ : List<Label>()
+{
+       this->edl = edl;
+       this->xml_tag = xml_tag;
+}
+
+Labels::~Labels()
+{
+       delete_all();
+}
+
+void Labels::dump(FILE *fp)
+{
+       for(Label *current = first; current; current = NEXT)
+       {
+               fprintf(fp, "  label: %f '%s'\n", current->position, current->textstr);
+       }
+}
+
+void Labels::insert_labels(Labels *labels, double start, double length, int paste_silence)
+{
+       Label *new_label;
+       Label *old_label;
+
+
+//printf("Labels::insert_labels 1 %f\n", start);
+
+// Insert silence in old labels
+       if(paste_silence)
+       {
+               for(old_label = first; old_label; old_label = old_label->next)
+               {
+                       if(old_label->position > start ||
+                               edl->equivalent(old_label->position, start))
+                               old_label->position += length;
+               }
+       }
+
+
+// Insert one new label at a time
+       for(new_label = labels->first; new_label; new_label = new_label->next)
+       {
+               int exists = 0;
+//printf("Labels::insert_labels 2 %f\n", new_label->position + start);
+
+// Check every old label for existence
+               for(old_label = first; old_label; old_label = old_label->next)
+               {
+                       if(edl->equivalent(old_label->position, new_label->position + start))
+                       {
+                               exists = 1;
+                               break;
+                       }
+                       else
+                       if(old_label->position > new_label->position + start)
+                               break;
+               }
+
+               if(!exists)
+               {
+                       if(old_label)
+                               insert_before(old_label, new Label(edl, this, new_label->position + start, new_label->textstr));
+                       else
+                               append(new Label(edl, this, new_label->position + start, new_label->textstr));
+               }
+       }
+}
+
+
+void Labels::insert_label(double position)
+{
+       int exists = 0;
+       Label *old_label = 0;
+
+// Check every old label for existence
+       for(old_label = first; old_label; old_label = old_label->next)
+       {
+               if(edl->equivalent(old_label->position, position))
+               {
+                       exists = 1;
+                       break;
+               }
+               else
+               if(old_label->position > position)
+                       break;
+       }
+
+       if(!exists)
+       {
+               if(old_label)
+                       insert_before(old_label, new Label(edl, this, position));
+               else
+                       append(new Label(edl, this, position));
+       }
+}
+
+
+int Labels::toggle_label(double start, double end)
+{
+       Label *current;
+//printf("Labels::toggle_label 1 %f %f\n", start, end);
+
+// handle selection start
+// find label the selectionstart is after
+       for(current = first;
+               current && current->position < start && !edl->equivalent(current->position, start);
+               current = NEXT)
+       {
+//printf("Labels::toggle_label 2 %f %f %f\n", start, end, current->position);
+               ;
+       }
+
+       if(current)
+       {
+//printf("Labels::toggle_label 3 %f %f %f\n", start, end, current->position);
+               if(edl->equivalent(current->position, start))
+               {        // remove it
+//printf("Labels::toggle_label 1\n");
+                       remove(current);
+               }
+               else
+               {        // insert before it
+                       current = insert_before(current, new Label(edl, this, start, ""));
+               }
+       }
+       else
+       {           // insert after last
+//printf("Labels::toggle_label 1\n");
+               current = append(new Label(edl, this, start, ""));
+       }
+
+// handle selection end
+       if(!EQUIV(start, end))
+       {
+//printf("Labels::toggle_label 2 %.16e %.16e\n", start, end);
+// find label the selectionend is after
+               for(current = first;
+                       current && current->position < end && !edl->equivalent(current->position, end);
+                       current = NEXT)
+               {
+                       ;
+               }
+
+               if(current)
+               {
+                       if(edl->equivalent(current->position, end))
+                       {
+                               remove(current);
+                       }
+                       else
+                       {
+                               current = insert_before(current, new Label(edl, this, end, ""));
+                       }
+               }
+               else
+               {
+                       current = append(new Label(edl, this, end, ""));
+               }
+       }
+       return 0;
+}
+
+Label *Labels::add_label(double position)
+{
+       Label *current;
+       for(current = first;
+               current && current->position < position;
+               current = NEXT)
+       {
+               if( edl->equivalent(current->position, position) ) return 0;
+       }
+
+       if(current)
+       {
+               current = insert_before(current, new Label(edl, this, position));
+       }
+       else
+       {
+               current = append(new Label(edl, this, position));
+       }
+       return current;
+}
+
+int Labels::delete_all()
+{
+       while(last)
+               remove(last);
+       return 0;
+}
+
+int Labels::copy(double start, double end, FileXML *xml)
+{
+       xml->tag.set_title("LABELS");
+       xml->append_tag();
+       xml->append_newline();
+
+       Label *current;
+       for(current = label_of(start);
+               current && current->position <= end;
+               current = NEXT)
+       {
+               xml->tag.set_title("LABEL");
+               xml->tag.set_property("TIME", (double)current->position - start);
+               xml->tag.set_property("TEXTSTR", current->textstr);
+//printf("Labels::copy %f\n", current->position - start);
+               xml->append_tag();
+               xml->tag.set_title("/LABEL");
+               xml->append_tag();
+               xml->append_newline();
+       }
+
+       xml->tag.set_title("/LABELS");
+       xml->append_tag();
+       xml->append_newline();
+       xml->append_newline();
+       return 0;
+}
+
+int Labels::copy_length(long start, long end) // return number of Labels in selection
+{
+       int result = 0;
+       Label *current;
+
+       for(current = label_of(start); current && current->position <= end; current = NEXT)
+       {
+               result++;
+       }
+       return result;
+}
+
+void Labels::copy_from(Labels *labels)
+{
+       while(last) delete last;
+
+       for(Label *current = labels->first; current; current = NEXT)
+       {
+               append(new Label(edl, this, current->position, current->textstr));
+       }
+}
+
+
+Labels& Labels::operator=(Labels &that)
+{
+       copy_from(&that);
+printf("Labels::operator= 1\n");
+       return *this;
+}
+
+
+int Labels::save(FileXML *xml)
+// Note: Normally the saving of Labels is done by Labels::copy()
+{
+       xml->tag.set_title("LABELS");
+       xml->append_tag();
+       xml->append_newline();
+
+       Label *current;
+
+       for(current = first; current; current = NEXT)
+       {
+               xml->tag.set_title("LABEL");
+               xml->tag.set_property("TIME", (double)current->position);
+               xml->tag.set_property("TEXTSTR", current->textstr);
+               xml->append_tag();
+               xml->tag.set_title("/LABEL");
+               xml->append_tag();
+               xml->append_newline();
+       }
+
+       xml->append_newline();
+       xml->tag.set_title("/LABELS");
+       xml->append_tag();
+       xml->append_newline();
+       xml->append_newline();
+       return 0;
+}
+
+int Labels::load(FileXML *xml, uint32_t load_flags)
+{
+       int result = 0;
+       char string1[BCTEXTLEN], string2[BCTEXTLEN];
+
+       sprintf(string1, "/%s", xml_tag);
+       strcpy(string2, xml_tag);
+       string2[strlen(string2) - 1] = 0;
+
+       do{
+               result = xml->read_tag();
+               if(!result)
+               {
+                       if(xml->tag.title_is(string1))
+                       {
+                               result = 1;
+                       }
+                       else
+                       if(xml->tag.title_is(string2))
+                       {
+                               double position = xml->tag.get_property("TIME", (double)-1);
+                               if(position < 0)
+                                       position = xml->tag.get_property("SAMPLE", (double)-1);
+//printf("Labels::load %f\n", position);
+                               if(position > -1)
+                               {
+                                       Label *current = label_of(position);
+                                       current = insert_before(current, new Label(edl, this, position, ""));
+                                       xml->tag.get_property("TEXTSTR", current->textstr);
+                               }
+                       }
+                       else
+                       if(xml->tag.title_is("INPOINT"))
+                       {
+                               double position = xml->tag.get_property("TIME", (double)-1);
+                               if(position < 0)
+                                       position = xml->tag.get_property("SAMPLE", (double)-1);
+                               if(position > -1)
+                               {
+                                       ;
+                               }
+                       }
+                       else
+                       if(xml->tag.title_is("OUTPOINT"))
+                       {
+                               double position = xml->tag.get_property("TIME", (double)-1);
+                               if(position < 0)
+                                       position = xml->tag.get_property("SAMPLE", (double)-1);
+                               if(position > -1)
+                               {
+                                       ;
+                               }
+                       }
+               }
+       }while(!result);
+       return 0;
+}
+
+
+
+int Labels::clear(double start, double end, int follow)
+{
+       Label *current;
+       Label *next;
+
+//printf("Labels::clear 1\n");
+       current = label_of(start);
+//printf("Labels::clear 2\n");
+// remove selected labels
+       while(current && current->position < end)
+       {
+               next = NEXT;
+               delete current;
+               current = next;
+       }
+// Shift later labels
+//printf("Labels::clear 3\n");
+       if(follow)
+       {
+               while(current)
+               {
+                       current->position -= end - start;   // shift labels forward
+                       current = NEXT;
+               }
+//printf("Labels::clear 4\n");
+               optimize();
+//printf("Labels::clear 5\n");
+       }
+
+       return 0;
+}
+
+
+Label* Labels::prev_label(double position)
+{
+       Label *current;
+
+// Test for label under cursor position
+       for(current = first;
+               current && !edl->equivalent(current->position, position);
+               current = NEXT)
+               ;
+
+// Test for label after cursor position
+       if(!current)
+               for(current = first;
+                       current && current->position < position;
+                       current = NEXT)
+                       ;
+
+// Test for label before cursor position
+       if(!current)
+               current = last;
+       else
+// Get previous label
+               current = PREVIOUS;
+
+       return current;
+}
+
+Label* Labels::next_label(double position)
+{
+       Label *current;
+
+// Test for label under cursor position
+       for(current = first;
+               current && !edl->equivalent(current->position, position);
+               current = NEXT)
+               ;
+
+// Test for label before cursor position
+       if(!current)
+               for(current = last;
+                       current && current->position > position;
+                       current = PREVIOUS)
+                       ;
+
+// Test for label after cursor position
+       if(!current)
+               current = first;
+       else
+// Get next label
+               current = NEXT;
+
+       return current;
+}
+
+int Labels::insert(double start, double length)
+{      // shift every label including the first one back
+       Label *current;
+
+       for(current = label_of(start); current; current = NEXT)
+       {
+               current->position += length;
+       }
+       return 0;
+}
+
+int Labels::paste_silence(double start, double end)
+{
+       insert(start, end - start);
+       optimize();
+       return 0;
+}
+
+int Labels::modify_handles(double oldposition,
+       double newposition,
+       int currentend,
+       int handle_mode,
+       int edit_labels)
+{
+       if(edit_labels &&
+               handle_mode == MOVE_ALL_EDITS)
+       {
+               if(currentend == 0)          // left handle
+               {
+                       if(newposition < oldposition)
+                       {
+                               insert(oldposition, oldposition - newposition);    // shift all labels right
+                       }
+                       else
+                       {
+                               clear(oldposition, newposition);   // clear selection
+                       }
+               }
+               else
+               {                            // right handle
+                       if(newposition < oldposition)
+                       {
+                               clear(newposition, oldposition);
+                       }
+                       else
+                       {
+                               insert(oldposition, newposition - oldposition);
+                       }
+               }
+       }
+       return 0;
+}
+
+int Labels::optimize()
+{
+       int result = 1;
+       Label *current;
+
+       while(result)
+       {
+               result = 0;
+
+               for(current = first; current && NEXT && !result;)
+               {
+                       Label *next = NEXT;
+                       if(current->position == next->position)
+                       {
+                               delete current;
+                               result  = 1;
+                       }
+                       current = next;
+               }
+       }
+       return 0;
+}
+
+Label* Labels::label_of(double position)
+{
+       Label *current;
+
+       for(current = first; current; current = NEXT)
+       {
+               if(current->position >= position) return current;
+       }
+       return 0;
+}
+
+
+
+
+
+
+
+
+
+
+Label::Label()
+ : ListItem<Label>()
+{
+}
+
+Label::Label(EDL *edl, Labels *labels, double position, const char *textstr)
+ : ListItem<Label>()
+{
+       this->edl = edl;
+       this->labels = labels;
+       this->position = position;
+       strcpy(this->textstr, textstr ? textstr : "");
+}
+
+
+Label::~Label()
+{
+//     if(toggle) delete toggle;
+}
+
+LabelToggle::LabelToggle(MWindow *mwindow,
+       Label *label,
+       int x,
+       int y,
+       long position)
+ : BC_Label(x, y, 0)
+{
+       this->mwindow = mwindow;
+       this->label = label;
+}
+
+LabelToggle::~LabelToggle() { }
+
+int LabelToggle::handle_event()
+{
+       return 0;
+}
+