Merge CV, ver=5.1; ops/methods from HV, and interface from CV where possible
[goodguy/history.git] / cinelerra-5.1 / cinelerra / keyframepopup.C
diff --git a/cinelerra-5.1/cinelerra/keyframepopup.C b/cinelerra-5.1/cinelerra/keyframepopup.C
new file mode 100644 (file)
index 0000000..303f599
--- /dev/null
@@ -0,0 +1,472 @@
+
+/*
+ * 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 "cwindow.h"
+#include "edl.h"
+#include "keyframe.h"
+#include "keyframepopup.h"
+#include "language.h"
+#include "mainundo.h"
+#include "mwindow.h"
+#include "mwindowgui.h"
+#include "localsession.h"
+#include "cwindowgui.h" 
+#include "cpanel.h"
+#include "patchbay.h"
+#include "patchgui.h" 
+#include "apatchgui.h"
+#include "vpatchgui.h"
+#include "track.h"
+#include "maincursor.h"
+#include "bcwindowbase.h"
+#include "filexml.h"
+#include "edlsession.h"
+#include "autos.h"
+
+KeyframePopup::KeyframePopup(MWindow *mwindow, MWindowGUI *gui)
+ : BC_PopupMenu(0, 0, 0, "", 0)
+{
+       this->mwindow = mwindow;
+       this->gui = gui;
+       key_show = 0;
+       key_delete = 0;
+       key_copy = 0;
+       key_smooth = 0;
+       key_linear = 0;
+       key_free = 0;
+       key_mbar = 0;
+       key_mode_displayed = false;
+}
+
+KeyframePopup::~KeyframePopup()
+{
+       if( !key_mode_displayed ) {
+               delete key_mbar;
+               delete key_smooth;
+               delete key_linear;
+               delete key_free_t;
+               delete key_free;
+       }
+}
+
+void KeyframePopup::create_objects()
+{
+       add_item(key_show = new KeyframePopupShow(mwindow, this));
+       add_item(key_delete = new KeyframePopupDelete(mwindow, this));
+       add_item(key_copy = new KeyframePopupCopy(mwindow, this));
+       add_item(key_edit = new KeyframePopupEdit(mwindow, this));
+
+       key_mbar   = new BC_MenuItem("-");
+       key_smooth = new KeyframePopupCurveMode(mwindow, this, FloatAuto::SMOOTH);
+       key_linear = new KeyframePopupCurveMode(mwindow, this, FloatAuto::LINEAR);
+       key_free_t = new KeyframePopupCurveMode(mwindow, this, FloatAuto::TFREE );
+       key_free   = new KeyframePopupCurveMode(mwindow, this, FloatAuto::FREE  );
+}
+
+int KeyframePopup::update(Plugin *plugin, KeyFrame *keyframe)
+{
+       this->keyframe_plugin = plugin;
+       this->keyframe_auto = keyframe;
+       this->keyframe_autos = 0;
+       this->keyframe_automation = 0;
+       handle_curve_mode(0, 0);
+       return 0;
+}
+
+int KeyframePopup::update(Automation *automation, Autos *autos, Auto *auto_keyframe)
+{
+       this->keyframe_plugin = 0;
+       this->keyframe_automation = automation;
+       this->keyframe_autos = autos;
+       this->keyframe_auto = auto_keyframe;
+       handle_curve_mode(autos, auto_keyframe);
+
+       /* snap to cursor */
+       double current_position = mwindow->edl->local_session->get_selectionstart(1);
+       double new_position = keyframe_automation->track->from_units(keyframe_auto->position);
+       mwindow->edl->local_session->set_selectionstart(new_position);
+       mwindow->edl->local_session->set_selectionend(new_position);
+       if (current_position != new_position)
+       {
+               mwindow->edl->local_session->set_selectionstart(new_position);
+               mwindow->edl->local_session->set_selectionend(new_position);
+               mwindow->gui->lock_window();
+               mwindow->gui->update(1, 1, 1, 1, 1, 1, 0);      
+               mwindow->gui->unlock_window();
+       }
+       return 0;
+}
+
+void KeyframePopup::handle_curve_mode(Autos *autos, Auto *auto_keyframe)
+// determines the type of automation node. if floatauto, adds
+// menu entries showing the curve mode of the node
+{
+       if(!key_mode_displayed && autos && autos->get_type() == AUTOMATION_TYPE_FLOAT)
+       { // append additional menu entries showing the curve_mode
+               add_item(key_mbar);
+               add_item(key_smooth);
+               add_item(key_linear);
+               add_item(key_free_t);
+               add_item(key_free);
+               key_mode_displayed = true;
+       }
+       else if(key_mode_displayed && (!autos || autos->get_type() != AUTOMATION_TYPE_FLOAT))
+       { // remove additional menu entries
+               remove_item(key_free);
+               remove_item(key_free_t);
+               remove_item(key_linear);
+               remove_item(key_smooth);
+               remove_item(key_mbar);
+               key_mode_displayed = false;
+       }
+       if(key_mode_displayed && auto_keyframe)
+       { // set checkmarks to display current mode
+               key_smooth->toggle_mode((FloatAuto*)auto_keyframe);
+               key_linear->toggle_mode((FloatAuto*)auto_keyframe);
+               key_free_t->toggle_mode((FloatAuto*)auto_keyframe);
+               key_free  ->toggle_mode((FloatAuto*)auto_keyframe);
+       }
+}
+
+KeyframePopupDelete::KeyframePopupDelete(MWindow *mwindow, KeyframePopup *popup)
+ : BC_MenuItem(_("Delete keyframe"))
+{
+       this->mwindow = mwindow;
+       this->popup = popup;
+}
+
+KeyframePopupDelete::~KeyframePopupDelete()
+{
+}
+
+int KeyframePopupDelete::handle_event()
+{
+       mwindow->undo->update_undo_before(_("delete keyframe"), 0);
+       delete popup->keyframe_auto;
+       mwindow->undo->update_undo_after(_("delete keyframe"), LOAD_ALL);
+
+       mwindow->save_backup();
+       mwindow->gui->update(0, 1,      // 1 for incremental drawing.  2 for full refresh
+               0, 0, 0, 0, 0);
+       mwindow->update_plugin_guis();
+       mwindow->restart_brender();
+       mwindow->sync_parameters(CHANGE_EDL);
+
+       return 1;
+}
+
+KeyframePopupShow::KeyframePopupShow(MWindow *mwindow, KeyframePopup *popup)
+ : BC_MenuItem(_("Show keyframe settings"))
+{
+       this->mwindow = mwindow;
+       this->popup = popup;
+}
+
+KeyframePopupShow::~KeyframePopupShow()
+{
+}
+
+int KeyframePopupShow::handle_event()
+{
+       if (popup->keyframe_plugin)
+       {
+               mwindow->update_plugin_guis();
+               mwindow->show_plugin(popup->keyframe_plugin);
+       } else
+       if (popup->keyframe_automation)
+       {
+/*
+
+               mwindow->cwindow->gui->lock_window();
+               int show_window = 1;
+               if (popup->keyframe_autos == (Autos *)popup->keyframe_automation->projector_autos ||
+                  popup->keyframe_autos == (Autos *)popup->keyframe_automation->pzoom_autos)
+                  
+               {
+                       mwindow->cwindow->gui->set_operation(CWINDOW_PROJECTOR);        
+               } else
+               if (popup->keyframe_autos == (Autos *)popup->keyframe_automation->camera_autos ||
+                  popup->keyframe_autos == (Autos *)popup->keyframe_automation->czoom_autos)
+                  
+               {
+                       mwindow->cwindow->gui->set_operation(CWINDOW_CAMERA);   
+               } else
+               if (popup->keyframe_autos == (Autos *)popup->keyframe_automation->mode_autos)
+                  
+               {
+                       // no window to be shown
+                       show_window = 0;
+                       // first find the appropriate patchgui
+                       PatchBay *patchbay = mwindow->gui->patchbay;
+                       PatchGUI *patchgui = 0;
+                       for (int i = 0; i < patchbay->patches.total; i++)
+                               if (patchbay->patches.values[i]->track == popup->keyframe_automation->track)
+                                       patchgui = patchbay->patches.values[i];         
+                       if (patchgui != 0)
+                       {
+// FIXME: repositioning of the listbox needs support in guicast
+//                             int cursor_x = popup->get_relative_cursor_x();
+//                             int cursor_y = popup->get_relative_cursor_y();
+//                             vpatchgui->mode->reposition_window(cursor_x, cursor_y);
+
+
+// Open the popup menu
+                               VPatchGUI *vpatchgui = (VPatchGUI *)patchgui;
+                               vpatchgui->mode->activate_menu();
+                       }
+               } else
+               if (popup->keyframe_autos == (Autos *)popup->keyframe_automation->mask_autos)
+                  
+               {
+                       mwindow->cwindow->gui->set_operation(CWINDOW_MASK);     
+               } else
+               if (popup->keyframe_autos == (Autos *)popup->keyframe_automation->pan_autos)
+                  
+               {
+                       // no window to be shown
+                       show_window = 0;
+                       // first find the appropriate patchgui
+                       PatchBay *patchbay = mwindow->gui->patchbay;
+                       PatchGUI *patchgui = 0;
+                       for (int i = 0; i < patchbay->patches.total; i++)
+                               if (patchbay->patches.values[i]->track == popup->keyframe_automation->track)
+                                       patchgui = patchbay->patches.values[i];         
+                       if (patchgui != 0)
+                       {
+// Open the popup menu at current mouse position
+                               APatchGUI *apatchgui = (APatchGUI *)patchgui;
+                               int cursor_x = popup->get_relative_cursor_x();
+                               int cursor_y = popup->get_relative_cursor_y();
+                               apatchgui->pan->activate(cursor_x, cursor_y);
+                       }
+                       
+
+               } else
+               if (popup->keyframe_autos == (Autos *)popup->keyframe_automation->fade_autos)
+                  
+               {
+                       // no window to be shown, so do nothing
+                       // IDEA: open window for fading
+                       show_window = 0;
+               } else
+               if (popup->keyframe_autos == (Autos *)popup->keyframe_automation->mute_autos)
+                  
+               {
+                       // no window to be shown, so do nothing
+                       // IDEA: directly switch
+                       show_window = 0;
+               } else;
+               
+
+// ensure bringing to front
+               if (show_window)
+               {
+                       ((CPanelToolWindow *)(mwindow->cwindow->gui->composite_panel->operation[CWINDOW_TOOL_WINDOW]))->set_shown(0);
+                       ((CPanelToolWindow *)(mwindow->cwindow->gui->composite_panel->operation[CWINDOW_TOOL_WINDOW]))->set_shown(1);
+               }
+               mwindow->cwindow->gui->unlock_window();
+
+
+*/
+       }
+       return 1;
+}
+
+
+
+KeyframePopupCopy::KeyframePopupCopy(MWindow *mwindow, KeyframePopup *popup)
+ : BC_MenuItem(_("Copy keyframe"))
+{
+       this->mwindow = mwindow;
+       this->popup = popup;
+}
+
+KeyframePopupCopy::~KeyframePopupCopy()
+{
+}
+
+int KeyframePopupCopy::handle_event()
+{
+/*
+       FIXME:
+       we want to copy just keyframe under cursor, NOT all keyframes at this frame
+       - very hard to do, so this is good approximation for now...
+*/
+       
+#if 0
+       if (popup->keyframe_automation)
+       {
+               FileXML file;
+               EDL *edl = mwindow->edl;
+               Track *track = popup->keyframe_automation->track;
+               int64_t position = popup->keyframe_auto->position;
+               AutoConf autoconf;
+// first find out type of our auto
+               autoconf.set_all(0);
+               if (popup->keyframe_autos == (Autos *)popup->keyframe_automation->projector_autos)
+                       autoconf.projector = 1;
+               else if (popup->keyframe_autos == (Autos *)popup->keyframe_automation->pzoom_autos)
+                       autoconf.pzoom = 1;
+               else if (popup->keyframe_autos == (Autos *)popup->keyframe_automation->camera_autos)
+                       autoconf.camera = 1;
+               else if (popup->keyframe_autos == (Autos *)popup->keyframe_automation->czoom_autos)
+                       autoconf.czoom = 1;             
+               else if (popup->keyframe_autos == (Autos *)popup->keyframe_automation->mode_autos)
+                       autoconf.mode = 1;
+               else if (popup->keyframe_autos == (Autos *)popup->keyframe_automation->mask_autos)
+                       autoconf.mask = 1;
+               else if (popup->keyframe_autos == (Autos *)popup->keyframe_automation->pan_autos)
+                       autoconf.pan = 1;                  
+               else if (popup->keyframe_autos == (Autos *)popup->keyframe_automation->fade_autos)
+                       autoconf.fade = 1;
+               else if (popup->keyframe_autos == (Autos *)popup->keyframe_automation->mute_autos)
+                       autoconf.mute = 1;              
+
+
+// now create a clipboard
+               file.tag.set_title("AUTO_CLIPBOARD");
+               file.tag.set_property("LENGTH", 0);
+               file.tag.set_property("FRAMERATE", edl->session->frame_rate);
+               file.tag.set_property("SAMPLERATE", edl->session->sample_rate);
+               file.append_tag();
+               file.append_newline();
+               file.append_newline();
+
+/*             track->copy_automation(position, 
+                       position, 
+                       &file,
+                       0,
+                       0);
+                       */
+               file.tag.set_title("TRACK");
+// Video or audio
+               track->save_header(&file);
+               file.append_tag();
+               file.append_newline();
+
+               track->automation->copy(position, 
+                       position, 
+                       &file,
+                       0,
+                       0,
+                       &autoconf);
+               
+               
+               
+               file.tag.set_title("/TRACK");
+               file.append_tag();
+               file.append_newline();
+               file.append_newline();
+               file.append_newline();
+               file.append_newline();
+
+
+
+               file.tag.set_title("/AUTO_CLIPBOARD");
+               file.append_tag();
+               file.append_newline();
+               file.terminate_string();
+
+               mwindow->gui->lock_window();
+               mwindow->gui->get_clipboard()->to_clipboard(file.string, 
+                       strlen(file.string), 
+                       SECONDARY_SELECTION);
+               mwindow->gui->unlock_window();
+
+       } else
+#endif
+               mwindow->copy_automation();
+       return 1;
+}
+
+
+
+KeyframePopupCurveMode::KeyframePopupCurveMode(
+       MWindow *mwindow, 
+       KeyframePopup *popup, 
+       int curve_mode)
+ : BC_MenuItem( get_labeltext(curve_mode))
+{
+       this->curve_mode = curve_mode;
+       this->mwindow = mwindow;
+       this->popup = popup;
+}
+
+KeyframePopupCurveMode::~KeyframePopupCurveMode() { }
+
+
+const char* KeyframePopupCurveMode::get_labeltext(int mode)
+{
+       switch(mode) {
+       case FloatAuto::SMOOTH: return _("smooth curve");
+       case FloatAuto::LINEAR: return _("linear segments");
+       case FloatAuto::TFREE:  return _("tangent edit");
+       case FloatAuto::FREE:   return _("disjoint edit");
+       }
+       return "misconfigured";
+}
+
+
+void KeyframePopupCurveMode::toggle_mode(FloatAuto *keyframe)
+{
+       set_checked(curve_mode == keyframe->curve_mode);
+}
+
+
+int KeyframePopupCurveMode::handle_event()
+{
+       if (popup->keyframe_autos && 
+           popup->keyframe_autos->get_type() == AUTOMATION_TYPE_FLOAT)
+       {
+               mwindow->undo->update_undo_before(_("change keyframe curve mode"), 0);
+               ((FloatAuto*)popup->keyframe_auto)->
+                       change_curve_mode((FloatAuto::t_mode)curve_mode);
+               
+               // if we switched to some "auto" mode, this may imply a
+               // real change to parameters, so this needs to be undoable...
+               mwindow->undo->update_undo_after(_("change keyframe curve mode"), LOAD_ALL);
+               mwindow->save_backup();
+               
+               mwindow->gui->update(0, 1, 0,0,0,0,0); // incremental redraw for canvas
+               mwindow->cwindow->update(0,0, 1, 0,0); // redraw tool window in compositor
+               mwindow->update_plugin_guis();
+               mwindow->restart_brender();
+               mwindow->sync_parameters(CHANGE_EDL);
+       }
+       return 1;
+}
+
+
+KeyframePopupEdit::KeyframePopupEdit(MWindow *mwindow, KeyframePopup *popup)
+ : BC_MenuItem(_("Edit Params..."))
+{
+       this->mwindow = mwindow;
+       this->popup = popup;
+}
+
+int KeyframePopupEdit::handle_event()
+{
+       mwindow->show_keyframe_gui(popup->keyframe_plugin);
+       return 1;
+}
+
+
+