reload plugin btn in prefs, speed gang fader tweaks
[goodguy/history.git] / cinelerra-5.1 / cinelerra / keyframepopup.C
index 13f2af0daf4503490fd8dd8d674ae1c8f231d0ec..7624da1631574fc7a8d16471c9a4f70110ec8f5c 100644 (file)
@@ -2,35 +2,39 @@
 /*
  * 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 "apatchgui.h"
+#include "atrack.h"
 #include "autoconf.h"
 #include "autos.h"
 #include "bcwindowbase.h"
 #include "cpanel.h"
-#include "cwindowgui.h" 
+#include "cwindowgui.h"
 #include "cwindow.h"
 #include "edl.h"
 #include "edlsession.h"
 #include "filexml.h"
+#include "floatauto.h"
 #include "gwindow.h"
 #include "gwindowgui.h"
+#include "intauto.h"
+#include "keys.h"
 #include "keyframe.h"
 #include "keyframepopup.h"
 #include "language.h"
 #include "mwindowgui.h"
 #include "mwindow.h"
 #include "patchbay.h"
-#include "patchgui.h" 
+#include "patchgui.h"
+#include "theme.h"
+#include "timelinepane.h"
 #include "track.h"
-#include "vpatchgui.h"
+#include "trackcanvas.h"
+#include "vtrack.h"
 
 KeyframePopup::KeyframePopup(MWindow *mwindow, MWindowGUI *gui)
  : BC_PopupMenu(0, 0, 0, "", 0)
 {
        this->mwindow = mwindow;
        this->gui = gui;
+       key_hide = 0;
        key_show = 0;
        key_delete = 0;
        key_copy = 0;
@@ -78,6 +86,7 @@ KeyframePopup::~KeyframePopup()
 void KeyframePopup::create_objects()
 {
        add_item(key_show = new KeyframePopupShow(mwindow, this));
+       add_item(key_hide = new KeyframePopupHide(mwindow, this));
        add_item(key_delete = new KeyframePopupDelete(mwindow, this));
        add_item(key_copy = new KeyframePopupCopy(mwindow, this));
 
@@ -91,6 +100,7 @@ void KeyframePopup::create_objects()
 
 int KeyframePopup::update(Plugin *plugin, KeyFrame *keyframe)
 {
+       key_show->set_text(_("Show Plugin Settings"));
        this->keyframe_plugin = plugin;
        this->keyframe_auto = keyframe;
        this->keyframe_autos = 0;
@@ -101,6 +111,7 @@ int KeyframePopup::update(Plugin *plugin, KeyFrame *keyframe)
 
 int KeyframePopup::update(Automation *automation, Autos *autos, Auto *auto_keyframe)
 {
+       key_show->set_text(_(GWindowGUI::auto_text[autos->autoidx]));
        this->keyframe_plugin = 0;
        this->keyframe_automation = automation;
        this->keyframe_autos = autos;
@@ -117,7 +128,7 @@ int KeyframePopup::update(Automation *automation, Autos *autos, Auto *auto_keyfr
                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->update(1, 1, 1, 1, 1, 1, 0);
                mwindow->gui->unlock_window();
        }
        return 0;
@@ -179,12 +190,14 @@ KeyframePopupDelete::~KeyframePopupDelete()
 int KeyframePopupDelete::handle_event()
 {
        mwindow->undo->update_undo_before(_("delete keyframe"), 0);
+       mwindow->speed_before();
        delete popup->keyframe_auto;
+       mwindow->speed_after(1);
        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);
+               0, 0, 0, 0, 0);
        mwindow->update_plugin_guis();
        mwindow->restart_brender();
        mwindow->sync_parameters(CHANGE_EDL);
@@ -192,6 +205,24 @@ int KeyframePopupDelete::handle_event()
        return 1;
 }
 
+KeyframePopupHide::KeyframePopupHide(MWindow *mwindow, KeyframePopup *popup)
+ : BC_MenuItem(_("Hide keyframe type"))
+{
+       this->mwindow = mwindow;
+       this->popup = popup;
+}
+
+KeyframePopupHide::~KeyframePopupHide()
+{
+}
+
+int KeyframePopupHide::handle_event()
+{
+       if( popup->keyframe_autos )
+               mwindow->set_auto_visibility(popup->keyframe_autos, 0);
+       return 1;
+}
+
 KeyframePopupShow::KeyframePopupShow(MWindow *mwindow, KeyframePopup *popup)
  : BC_MenuItem(_("Show keyframe settings"))
 {
@@ -205,105 +236,102 @@ KeyframePopupShow::~KeyframePopupShow()
 
 int KeyframePopupShow::handle_event()
 {
-       if (popup->keyframe_plugin)
-       {
+       MWindowGUI *mgui = mwindow->gui;
+       CWindowGUI *cgui = mwindow->cwindow->gui;
+       int cx = mgui->get_relative_cursor_x()+15, cy = mgui->get_relative_cursor_y()-15;
+       delete mgui->keyvalue_popup;
+       mgui->keyvalue_popup = 0;
+
+       if( popup->keyframe_plugin ) {
                mwindow->update_plugin_guis();
                mwindow->show_plugin(popup->keyframe_plugin);
        }
        else if( popup->keyframe_automation ) {
-/*
-
-               mwindow->cwindow->gui->lock_window();
+               cgui->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
+
+               switch( popup->keyframe_autos->autoidx ) {
+               case AUTOMATION_CAMERA_X:
+               case AUTOMATION_CAMERA_Y:
+               case AUTOMATION_CAMERA_Z: {
+                       cgui->set_operation(CWINDOW_CAMERA);
+                       break; }
+
+               case AUTOMATION_PROJECTOR_X:
+               case AUTOMATION_PROJECTOR_Y:
+               case AUTOMATION_PROJECTOR_Z: {
+                       cgui->set_operation(CWINDOW_PROJECTOR);
+                       break; }
+
+               case AUTOMATION_MASK: {
+                       cgui->set_operation(CWINDOW_MASK);
+                       break; }
+
+               default: {
                        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);
+                       PatchGUI *patchgui = mwindow->get_patchgui(popup->keyframe_automation->track);
+                       if( !patchgui ) break;
+
+                       switch( popup->keyframe_autos->autoidx ) {
+                       case AUTOMATION_MODE: {
+                               VKeyModePatch *mode = new VKeyModePatch(mwindow, (VPatchGUI *)patchgui);
+                               mgui->add_subwindow(mode);
+                               mode->create_objects();
+                               mode->activate_menu();
+                               mgui->keyvalue_popup = mode;
+                       break; }
+
+                       case AUTOMATION_PAN: {
+                               AKeyPanPatch *pan = new AKeyPanPatch(mwindow, (APatchGUI *)patchgui);
+                               mgui->add_subwindow(pan);
+                               pan->create_objects();
+                               pan->activate(cx, cy);
+                               mgui->keyvalue_popup = pan;
+                       break; }
+
+                       case AUTOMATION_FADE: {
+                               switch( patchgui->data_type ) {
+                               case TRACK_AUDIO: {
+                                       AKeyFadePatch *fade = new AKeyFadePatch(mwindow, (APatchGUI *)patchgui, cx, cy);
+                                       mgui->add_subwindow(fade);
+                                       fade->create_objects();
+                                       mgui->keyvalue_popup = fade;
+                                       break; }
+                               case TRACK_VIDEO: {
+                                       VKeyFadePatch *fade = new VKeyFadePatch(mwindow, (VPatchGUI *)patchgui, cx, cy);
+                                       mgui->add_subwindow(fade);
+                                       fade->create_objects();
+                                       mgui->keyvalue_popup = fade;
+                                       break; }
+                               }
+                               break; }
+
+                       case AUTOMATION_SPEED: {
+                               KeySpeedPatch *speed = new KeySpeedPatch(mwindow, patchgui, cx, cy);
+                               mgui->add_subwindow(speed);
+                               speed->create_objects();
+                               mgui->keyvalue_popup = speed;
+                               break; }
+
+                       case AUTOMATION_MUTE: {
+                               KeyMutePatch *mute = new KeyMutePatch(mwindow, (APatchGUI *)patchgui, cx, cy);
+                               mgui->add_subwindow(mute);
+                               mute->create_objects();
+                               mgui->keyvalue_popup = mute;
+                               break; }
                        }
-                       
-
-               } 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;
-               
+                       break; }
+               }
 
 // 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);
+               if( show_window ) {
+                       mwindow->show_cwindow();
+                       CPanelToolWindow *panel_tool_window =
+                               (CPanelToolWindow *)cgui->composite_panel->operation[CWINDOW_TOOL_WINDOW];
+                       panel_tool_window->set_shown(0);
+                       panel_tool_window->set_shown(1);
                }
-               mwindow->cwindow->gui->unlock_window();
-
-
-*/
+               cgui->unlock_window();
        }
        return 1;
 }
@@ -328,7 +356,7 @@ int KeyframePopupCopy::handle_event()
        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)
        {
@@ -346,17 +374,17 @@ int KeyframePopupCopy::handle_event()
                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;             
+                       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;                  
+                       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;              
+                       autoconf.mute = 1;
 
 
 // now create a clipboard
@@ -368,8 +396,8 @@ int KeyframePopupCopy::handle_event()
                file.append_newline();
                file.append_newline();
 
-/*             track->copy_automation(position, 
-                       position, 
+/*             track->copy_automation(position,
+                       position,
                        &file,
                        0,
                        0);
@@ -380,15 +408,12 @@ int KeyframePopupCopy::handle_event()
                file.append_tag();
                file.append_newline();
 
-               track->automation->copy(position, 
-                       position, 
+               track->automation->copy(position,
+                       position,
                        &file,
                        0,
                        0,
                        &autoconf);
-               
-               
-               
                file.tag.set_title("/TRACK");
                file.append_tag();
                file.append_newline();
@@ -396,17 +421,13 @@ int KeyframePopupCopy::handle_event()
                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->to_clipboard(file.string, strlen(file.string), SECONDARY_SELECTION);
                mwindow->gui->unlock_window();
 
        } else
@@ -418,8 +439,8 @@ int KeyframePopupCopy::handle_event()
 
 
 KeyframePopupCurveMode::KeyframePopupCurveMode(
-       MWindow *mwindow, 
-       KeyframePopup *popup, 
+       MWindow *mwindow,
+       KeyframePopup *popup,
        int curve_mode)
  : BC_MenuItem( get_labeltext(curve_mode))
 {
@@ -439,7 +460,7 @@ const char* KeyframePopupCurveMode::get_labeltext(int mode)
        case FloatAuto::TFREE:  return _("tangent edit");
        case FloatAuto::FREE:   return _("disjoint edit");
        }
-       return "misconfigured";
+       return _("misconfigured");
 }
 
 
@@ -451,18 +472,18 @@ void KeyframePopupCurveMode::toggle_mode(FloatAuto *keyframe)
 
 int KeyframePopupCurveMode::handle_event()
 {
-       if (popup->keyframe_autos && 
+       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();
@@ -501,7 +522,7 @@ KeyframeHidePopup::~KeyframeHidePopup()
 
 void KeyframeHidePopup::create_objects()
 {
-        add_item(new KeyframePopupHide(mwindow, this));
+       add_item(new KeyframeHideItem(mwindow, this));
 }
 
 int KeyframeHidePopup::update(Autos *autos)
@@ -510,61 +531,204 @@ int KeyframeHidePopup::update(Autos *autos)
        return 0;
 }
 
-KeyframePopupHide::KeyframePopupHide(MWindow *mwindow, KeyframeHidePopup *popup)
+KeyframeHideItem::KeyframeHideItem(MWindow *mwindow, KeyframeHidePopup *popup)
  : BC_MenuItem(_("Hide keyframe type"))
 {
        this->mwindow = mwindow;
        this->popup = popup;
 }
 
-int KeyframePopupHide::handle_event()
+
+int KeyframeHideItem::handle_event()
 {
-// Get the array index of the curve
-       int update_gui = 0;
-       if(popup->keyframe_autos)
-       {
-               if(popup->keyframe_autos->type == Autos::AUTOMATION_TYPE_PLUGIN)
-               {
-                       mwindow->edl->session->auto_conf->plugins = 0;
-                       update_gui = 1;
-               }
-               else
-               {
-                       Track *track = popup->keyframe_autos->track;
-                       if(track)
-                       {
-                               Automation *automation = track->automation;
-                               if(automation)
-                               {
-                                       for(int i = 0; i < AUTOMATION_TOTAL; i++)
-                                       {
-                                               if(automation->autos[i] == popup->keyframe_autos)
-                                               {
-                                                       mwindow->edl->session->auto_conf->autos[i] = 0;
-                                                       update_gui = 1;
-                                                       break;
-                                               }
-                                       }
-                               }
-                       }
-               }
+       if( popup->keyframe_autos )
+               mwindow->set_auto_visibility(popup->keyframe_autos, 0);
+       return 1;
+}
+
+
+
+KeyMutePatch::KeyMutePatch(MWindow *mwindow, PatchGUI *patch, int x, int y)
+ : BC_SubWindow(x, y, 100, 20, GWindowGUI::auto_colors[AUTOMATION_MUTE])
+{
+       this->mwindow = mwindow;
+       this->patch = patch;
+}
+
+void KeyMutePatch::create_objects()
+{
+       key_mute_checkbox = new KeyMuteValue(this);
+       add_subwindow(key_mute_checkbox);
+       key_mute_checkbox->activate();
+       show_window();
+}
+
+KeyMuteValue::KeyMuteValue(KeyMutePatch *key_mute_patch)
+ : BC_CheckBox(0,0, key_mute_patch->mwindow->
+       get_int_auto(key_mute_patch->patch, AUTOMATION_MUTE)->value,
+       _("Mute"), MEDIUMFONT, RED)
+{
+       this->key_mute_patch = key_mute_patch;
+}
+
+int KeyMuteValue::button_release_event()
+{
+       BC_CheckBox::button_release_event();
+       MWindowGUI *mgui = key_mute_patch->mwindow->gui;
+       delete mgui->keyvalue_popup;
+       mgui->keyvalue_popup = 0;
+       return 1;
+}
+
+int KeyMuteValue::handle_event()
+{
+       MWindow *mwindow = key_mute_patch->mwindow;
+       PatchGUI *patch = key_mute_patch->patch;
+
+       patch->change_source = 1;
+       double position = mwindow->edl->local_session->get_selectionstart(1);
+       Autos *mute_autos = patch->track->automation->autos[AUTOMATION_MUTE];
+       int need_undo = !mute_autos->auto_exists_for_editing(position);
+       mwindow->undo->update_undo_before(_("mute"), need_undo ? 0 : this);
+       IntAuto *current = (IntAuto*)mute_autos->get_auto_for_editing(position);
+       current->value = this->get_value();
+       mwindow->undo->update_undo_after(_("mute"), LOAD_AUTOMATION);
+       patch->change_source = 0;
+
+       mwindow->sync_parameters(CHANGE_PARAMS);
+       if( mwindow->edl->session->auto_conf->autos[AUTOMATION_MUTE] ) {
+               mwindow->gui->update_patchbay();
+               mwindow->gui->draw_overlays(1);
        }
+       return 1;
+}
 
-       if(update_gui)
-       {
-               mwindow->gui->update(0,
-                       1,      // 1 for incremental drawing.  2 for full refresh
-                       0,
-                       0,
-                       0,
-               0,   
-               0);
-               mwindow->gui->mainmenu->update_toggles(1);
-               mwindow->gui->unlock_window();
-               mwindow->gwindow->gui->update_toggles(1);
-               mwindow->gui->lock_window("KeyframePopupHide::handle_event");
+KeySpeedPatch::KeySpeedPatch(MWindow *mwindow, PatchGUI *patch, int x, int y)
+ : BC_SubWindow(x,y, 200,20, GWindowGUI::auto_colors[AUTOMATION_SPEED])
+{
+       this->mwindow = mwindow;
+       this->patch = patch;
+}
+
+void KeySpeedPatch::create_objects()
+{
+       int x = 0, y = 0;
+       float v = mwindow->get_float_auto(patch, AUTOMATION_SPEED)->get_value();
+       add_subwindow(key_speed_text = new KeySpeedText(this, x, y, 64, v));
+       x += key_speed_text->get_w();
+       VFrame **lok_images = mwindow->theme->get_image_set("lok");
+       int w1 = get_w() - x - lok_images[0]->get_w();
+       add_subwindow(key_speed_slider = new KeySpeedSlider(this, x, y, w1, v));
+       x += key_speed_slider->get_w();
+       add_subwindow(key_speed_ok = new KeySpeedOK(this, x, y, lok_images));
+       activate();
+       show_window();
+}
+
+int KeySpeedPatch::cursor_enter_event()
+{
+       if( is_event_win() )
+               mwindow->speed_before();
+       return 1;
+}
+
+int KeySpeedPatch::cursor_leave_event()
+{
+       if( is_event_win() ) {
+               mwindow->speed_after(1);
+               mwindow->resync_guis();
+       }
+       return 1;
+}
+
+void KeySpeedPatch::update(float v)
+{
+       key_speed_text->update(v);
+       key_speed_slider->update(v);
+       update_speed(v);
+}
+
+void KeySpeedPatch::update_speed(float v)
+{
+       patch->change_source = 1;
+       double position = mwindow->edl->local_session->get_selectionstart(1);
+       Track *track = patch->track;
+       Autos *speed_autos = track->automation->autos[AUTOMATION_SPEED];
+       int need_undo = !speed_autos->auto_exists_for_editing(position);
+
+       mwindow->undo->update_undo_before(_("speed"), need_undo ? 0 : this);
+       FloatAuto *current = (FloatAuto*)speed_autos->get_auto_for_editing(position);
+       float change = v - current->get_value();
+       current->set_value(v);
+       if( track->gang && track->record ) {
+               TrackCanvas *track_canvas = patch->patchbay->pane->canvas;
+               track_canvas->fill_ganged_autos(1, change, track, current);
+               track_canvas->update_ganged_autos(0, track, current);
+               track_canvas->clear_ganged_autos();
        }
+       mwindow->undo->update_undo_after(_("speed"), LOAD_AUTOMATION+LOAD_EDITS);
+       patch->change_source = 0;
+
+       mwindow->sync_parameters(CHANGE_PARAMS);
+       if(mwindow->edl->session->auto_conf->autos[AUTOMATION_SPEED]) {
+               mwindow->gui->draw_overlays(1);
+       }
+}
+
+KeySpeedOK::KeySpeedOK(KeySpeedPatch *key_speed_patch, int x, int y, VFrame **images)
+ : BC_Button(x, y, images)
+{
+       this->key_speed_patch = key_speed_patch;
+}
+
+int KeySpeedOK::handle_event()
+{
+       MWindow *mwindow = key_speed_patch->mwindow;
+       mwindow->speed_after(1);
+       mwindow->resync_guis();
+       MWindowGUI *mgui = mwindow->gui;
+       delete mgui->keyvalue_popup;
+       mgui->keyvalue_popup = 0;
+       return 1;
+}
 
+KeySpeedText::KeySpeedText(KeySpeedPatch *key_speed_patch, int x, int y, int w, float v)
+ : BC_TextBox(x, y, w, 1, v, 1, MEDIUMFONT, 2)
+{
+       this->key_speed_patch = key_speed_patch;
+}
+
+int KeySpeedText::handle_event()
+{
+       float v = atof(get_text());
+       key_speed_patch->update(v);
+       return get_keypress() != RETURN ? 1 :
+               key_speed_patch->key_speed_ok->handle_event();
+}
+
+KeySpeedSlider::KeySpeedSlider(KeySpeedPatch *key_speed_patch,
+               int x, int y, int w, float v)
+ : BC_FSlider(x, y, 0, w, w,
+       key_speed_patch->mwindow->edl->local_session->automation_mins[AUTOGROUPTYPE_SPEED],
+       key_speed_patch->mwindow->edl->local_session->automation_maxs[AUTOGROUPTYPE_SPEED],
+       v)
+{
+       this->key_speed_patch = key_speed_patch;
+       key_speed_patch->mwindow->speed_before();
+       set_precision(0.01);
+}
+
+KeySpeedSlider::~KeySpeedSlider()
+{
+}
+
+int KeySpeedSlider::handle_event()
+{
+       if( shift_down() ) {
+               update(1.0);
+               set_tooltip(get_caption());
+       }
+       key_speed_patch->update(get_value());
        return 1;
 }