Credit ffmpeg team with upgrade to 6.1
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / keyframepopup.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  * Copyright (C) 2003-2016 Cinelerra CV contributors
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  */
22
23 #include "apatchgui.h"
24 #include "atrack.h"
25 #include "autoconf.h"
26 #include "autos.h"
27 #include "bcwindowbase.h"
28 #include "cpanel.h"
29 #include "cwindowgui.h"
30 #include "cwindow.h"
31 #include "edl.h"
32 #include "edlsession.h"
33 #include "filexml.h"
34 #include "floatauto.h"
35 #include "gwindow.h"
36 #include "gwindowgui.h"
37 #include "intauto.h"
38 #include "keys.h"
39 #include "keyframe.h"
40 #include "keyframepopup.h"
41 #include "language.h"
42 #include "localsession.h"
43 #include "maincursor.h"
44 #include "mainmenu.h"
45 #include "mainundo.h"
46 #include "mwindowgui.h"
47 #include "mwindow.h"
48 #include "patchbay.h"
49 #include "patchgui.h"
50 #include "theme.h"
51 #include "timelinepane.h"
52 #include "track.h"
53 #include "trackcanvas.h"
54 #include "vtrack.h"
55
56 KeyframePopup::KeyframePopup(MWindow *mwindow, MWindowGUI *gui)
57  : BC_PopupMenu(0, 0, 0, "", 0)
58 {
59         this->mwindow = mwindow;
60         this->gui = gui;
61         key_hide = 0;
62         key_show = 0;
63         key_delete = 0;
64         key_copy = 0;
65         key_smooth = 0;
66         key_linear = 0;
67         key_free = 0;
68         key_mbar = 0;
69         key_mode_displayed = false;
70         key_edit_displayed = false;
71         popx = popy = 0;
72 }
73
74 KeyframePopup::~KeyframePopup()
75 {
76         if( !key_mode_displayed ) {
77                 delete key_mbar;
78                 delete key_smooth;
79                 delete key_linear;
80                 delete key_free_t;
81                 delete key_free;
82                 delete key_bump;
83         }
84         if( !key_edit_displayed ) {
85                 delete key_edit;
86         }
87 }
88
89 void KeyframePopup::create_objects()
90 {
91         add_item(key_show = new KeyframePopupShow(mwindow, this));
92         add_item(key_hide = new KeyframePopupHide(mwindow, this));
93         add_item(key_delete = new KeyframePopupDelete(mwindow, this));
94         add_item(key_copy = new KeyframePopupCopy(mwindow, this));
95
96         key_edit   = new KeyframePopupEdit(mwindow, this);
97         key_mbar   = new BC_MenuItem("-");
98         key_smooth = new KeyframePopupCurveMode(mwindow, this, FloatAuto::SMOOTH);
99         key_linear = new KeyframePopupCurveMode(mwindow, this, FloatAuto::LINEAR);
100         key_free_t = new KeyframePopupCurveMode(mwindow, this, FloatAuto::TFREE );
101         key_free   = new KeyframePopupCurveMode(mwindow, this, FloatAuto::FREE  );
102         key_bump   = new KeyframePopupCurveMode(mwindow, this, FloatAuto::BUMP  );
103 }
104
105 int KeyframePopup::update(Plugin *plugin, KeyFrame *keyframe)
106 {
107         gui->get_relative_cursor(popx, popy);
108         key_show->set_text(_("Show Plugin Settings"));
109         this->keyframe_plugin = plugin;
110         this->keyframe_auto = keyframe;
111         this->keyframe_autos = 0;
112         this->keyframe_automation = 0;
113         handle_curve_mode(0, 0);
114         return 0;
115 }
116
117 int KeyframePopup::update(Automation *automation, Autos *autos, Auto *auto_keyframe)
118 {
119         gui->get_relative_cursor(popx, popy);
120         key_show->set_text(_(GWindowGUI::auto_text[autos->autoidx]));
121         this->keyframe_plugin = 0;
122         this->keyframe_automation = automation;
123         this->keyframe_autos = autos;
124         this->keyframe_auto = auto_keyframe;
125         handle_curve_mode(autos, auto_keyframe);
126
127         /* snap to cursor */
128         double current_position = mwindow->edl->local_session->get_selectionstart(1);
129         double new_position = keyframe_automation->track->from_units(keyframe_auto->position);
130         mwindow->edl->local_session->set_selectionstart(new_position);
131         mwindow->edl->local_session->set_selectionend(new_position);
132         if (current_position != new_position)
133         {
134                 mwindow->edl->local_session->set_selectionstart(new_position);
135                 mwindow->edl->local_session->set_selectionend(new_position);
136                 mwindow->gui->lock_window();
137                 mwindow->gui->update(1, NORMAL_DRAW, 1, 1, 1, 1, 0);
138                 mwindow->gui->unlock_window();
139         }
140         return 0;
141 }
142
143 void KeyframePopup::handle_curve_mode(Autos *autos, Auto *auto_keyframe)
144 // determines the type of automation node. if floatauto, adds
145 // menu entries showing the curve mode of the node
146 {
147         deactivate();
148         if( !key_edit_displayed && keyframe_plugin ) {
149                 add_item(key_edit);
150                 key_edit_displayed = true;
151         }
152         else if( key_edit_displayed && !keyframe_plugin ) {
153                 remove_item(key_edit);
154                 key_edit_displayed = false;
155         }
156
157         if(!key_mode_displayed && autos && autos->get_type() == AUTOMATION_TYPE_FLOAT)
158         { // append additional menu entries showing the curve_mode
159                 add_item(key_mbar);
160                 add_item(key_smooth);
161                 add_item(key_linear);
162                 add_item(key_free_t);
163                 add_item(key_free);
164                 add_item(key_bump);
165                 key_mode_displayed = true;
166         }
167         else if(key_mode_displayed && (!autos || autos->get_type() != AUTOMATION_TYPE_FLOAT))
168         { // remove additional menu entries
169                 remove_item(key_bump);
170                 remove_item(key_free);
171                 remove_item(key_free_t);
172                 remove_item(key_linear);
173                 remove_item(key_smooth);
174                 remove_item(key_mbar);
175                 key_mode_displayed = false;
176         }
177         if(key_mode_displayed && auto_keyframe)
178         { // set checkmarks to display current mode
179                 key_smooth->toggle_mode((FloatAuto*)auto_keyframe);
180                 key_linear->toggle_mode((FloatAuto*)auto_keyframe);
181                 key_free_t->toggle_mode((FloatAuto*)auto_keyframe);
182                 key_free  ->toggle_mode((FloatAuto*)auto_keyframe);
183                 key_bump  ->toggle_mode((FloatAuto*)auto_keyframe);
184         }
185         activate();
186 }
187
188 KeyframePopupDelete::KeyframePopupDelete(MWindow *mwindow, KeyframePopup *popup)
189  : BC_MenuItem(_("Delete keyframe"))
190 {
191         this->mwindow = mwindow;
192         this->popup = popup;
193 }
194
195 KeyframePopupDelete::~KeyframePopupDelete()
196 {
197 }
198
199 int KeyframePopupDelete::handle_event()
200 {
201         mwindow->undo->update_undo_before(_("delete keyframe"), 0);
202         mwindow->speed_before();
203         delete popup->keyframe_auto;
204         mwindow->speed_after(1, 1);
205         mwindow->undo->update_undo_after(_("delete keyframe"), LOAD_ALL);
206
207         mwindow->save_backup();
208         mwindow->gui->update(0, NORMAL_DRAW,
209                 0, 0, 0, 0, 0);
210         mwindow->update_plugin_guis();
211         mwindow->restart_brender();
212         mwindow->sync_parameters(CHANGE_EDL);
213
214         return 1;
215 }
216
217 KeyframePopupHide::KeyframePopupHide(MWindow *mwindow, KeyframePopup *popup)
218  : BC_MenuItem(_("Hide keyframe type"))
219 {
220         this->mwindow = mwindow;
221         this->popup = popup;
222 }
223
224 KeyframePopupHide::~KeyframePopupHide()
225 {
226 }
227
228 int KeyframePopupHide::handle_event()
229 {
230         if( popup->keyframe_autos )
231                 mwindow->set_auto_visibility(popup->keyframe_autos, 0);
232         return 1;
233 }
234
235 KeyframePopupShow::KeyframePopupShow(MWindow *mwindow, KeyframePopup *popup)
236  : BC_MenuItem(_("Show keyframe settings"))
237 {
238         this->mwindow = mwindow;
239         this->popup = popup;
240 }
241
242 KeyframePopupShow::~KeyframePopupShow()
243 {
244 }
245
246 int KeyframePopupShow::handle_event()
247 {
248         MWindowGUI *mgui = mwindow->gui;
249         CWindowGUI *cgui = mwindow->cwindow->gui;
250         int cx = popup->popx, cy = popup->popy;
251         int xmargin = mgui->get_w() - xS(200);
252         int ymargin = mgui->get_h() - yS(50);
253         if( cx > xmargin ) cx = xmargin;
254         if( cy > ymargin ) cy = ymargin;
255         xmargin = xS(15);  ymargin = yS(15);
256         if( cx < xmargin ) cx = xmargin;
257         if( cy < ymargin ) cy = ymargin;
258         mgui->close_keyvalue_popup();
259
260         if( popup->keyframe_plugin ) {
261                 mwindow->update_plugin_guis();
262                 mwindow->show_plugin(popup->keyframe_plugin);
263         }
264         else if( popup->keyframe_automation ) {
265                 cgui->lock_window();
266                 int show_window = 1;
267
268                 switch( popup->keyframe_autos->autoidx ) {
269                 case AUTOMATION_CAMERA_X:
270                 case AUTOMATION_CAMERA_Y:
271                 case AUTOMATION_CAMERA_Z: {
272                         cgui->set_operation(CWINDOW_CAMERA);
273                         break; }
274
275                 case AUTOMATION_PROJECTOR_X:
276                 case AUTOMATION_PROJECTOR_Y:
277                 case AUTOMATION_PROJECTOR_Z: {
278                         cgui->set_operation(CWINDOW_PROJECTOR);
279                         break; }
280
281                 case AUTOMATION_MASK: {
282                         cgui->set_operation(CWINDOW_MASK);
283                         break; }
284
285                 default: {
286                         show_window = 0;
287                         PatchGUI *patchgui = mwindow->get_patchgui(popup->keyframe_automation->track);
288                         if( !patchgui ) break;
289
290                         switch( popup->keyframe_autos->autoidx ) {
291                         case AUTOMATION_MODE: {
292                                 VKeyModePatch *mode = new VKeyModePatch(mwindow, (VPatchGUI *)patchgui);
293                                 mgui->add_subwindow(mode);
294                                 mode->create_objects();
295                                 mode->activate_menu();
296                                 mgui->open_keyvalue_popup(mode);
297                         break; }
298
299                         case AUTOMATION_PAN: {
300                                 AKeyPanPatch *pan = new AKeyPanPatch(mwindow, (APatchGUI *)patchgui);
301                                 mgui->add_subwindow(pan);
302                                 pan->create_objects();
303                                 pan->activate(cx, cy);
304                                 mgui->open_keyvalue_popup(pan);
305                         break; }
306
307                         case AUTOMATION_FADE: {
308                                 FloatAuto *fade_auto = mwindow->get_float_auto(patchgui, AUTOMATION_FADE);
309                                 int bump = fade_auto->is_bump();
310                                 switch( patchgui->data_type ) {
311                                 case TRACK_AUDIO: {
312                                         AKeyFadePatch *fade = new AKeyFadePatch(mwindow,
313                                                         (APatchGUI *)patchgui, bump, cx, cy);
314                                         mgui->add_subwindow(fade);
315                                         fade->create_objects();
316                                         mgui->open_keyvalue_popup(fade);
317                                         break; }
318                                 case TRACK_VIDEO: {
319                                         VKeyFadePatch *fade = new VKeyFadePatch(mwindow,
320                                                         (VPatchGUI *)patchgui, bump, cx, cy);
321                                         mgui->add_subwindow(fade);
322                                         fade->create_objects();
323                                         mgui->open_keyvalue_popup(fade);
324                                         break; }
325                                 }
326                                 break; }
327
328                         case AUTOMATION_SPEED: {
329                                 FloatAuto *speed_auto = mwindow->get_float_auto(patchgui, AUTOMATION_SPEED);
330                                 int bump = speed_auto->is_bump();
331                                 KeySpeedPatch *speed = new KeySpeedPatch(mwindow, patchgui, bump, cx, cy);
332                                 mgui->add_subwindow(speed);
333                                 speed->create_objects();
334                                 mgui->open_keyvalue_popup(speed);
335                                 break; }
336
337                         case AUTOMATION_MUTE: {
338                                 KeyMutePatch *mute = new KeyMutePatch(mwindow, (APatchGUI *)patchgui, cx, cy);
339                                 mgui->add_subwindow(mute);
340                                 mute->create_objects();
341                                 mgui->open_keyvalue_popup(mute);
342                                 break; }
343                         }
344                         break; }
345                 }
346
347 // ensure bringing to front
348                 if( show_window ) {
349                         mwindow->show_cwindow();
350                         CPanelToolWindow *panel_tool_window =
351                                 (CPanelToolWindow *)cgui->composite_panel->operation[CWINDOW_TOOL_WINDOW];
352                         panel_tool_window->set_shown(0);
353                         panel_tool_window->set_shown(1);
354                 }
355                 cgui->unlock_window();
356         }
357         return 1;
358 }
359
360
361
362 KeyframePopupCopy::KeyframePopupCopy(MWindow *mwindow, KeyframePopup *popup)
363  : BC_MenuItem(_("Copy keyframe"))
364 {
365         this->mwindow = mwindow;
366         this->popup = popup;
367 }
368
369 KeyframePopupCopy::~KeyframePopupCopy()
370 {
371 }
372
373 int KeyframePopupCopy::handle_event()
374 {
375 /*
376         FIXME:
377         we want to copy just keyframe under cursor, NOT all keyframes at this frame
378         - very hard to do, so this is good approximation for now...
379 */
380
381 #if 0
382         if (popup->keyframe_automation)
383         {
384                 FileXML file;
385                 EDL *edl = mwindow->edl;
386                 Track *track = popup->keyframe_automation->track;
387                 int64_t position = popup->keyframe_auto->position;
388                 AutoConf autoconf;
389 // first find out type of our auto
390                 autoconf.set_all(0);
391                 if (popup->keyframe_autos == (Autos *)popup->keyframe_automation->projector_autos)
392                         autoconf.projector = 1;
393                 else if (popup->keyframe_autos == (Autos *)popup->keyframe_automation->pzoom_autos)
394                         autoconf.pzoom = 1;
395                 else if (popup->keyframe_autos == (Autos *)popup->keyframe_automation->camera_autos)
396                         autoconf.camera = 1;
397                 else if (popup->keyframe_autos == (Autos *)popup->keyframe_automation->czoom_autos)
398                         autoconf.czoom = 1;
399                 else if (popup->keyframe_autos == (Autos *)popup->keyframe_automation->mode_autos)
400                         autoconf.mode = 1;
401                 else if (popup->keyframe_autos == (Autos *)popup->keyframe_automation->mask_autos)
402                         autoconf.mask = 1;
403                 else if (popup->keyframe_autos == (Autos *)popup->keyframe_automation->pan_autos)
404                         autoconf.pan = 1;
405                 else if (popup->keyframe_autos == (Autos *)popup->keyframe_automation->fade_autos)
406                         autoconf.fade = 1;
407                 else if (popup->keyframe_autos == (Autos *)popup->keyframe_automation->mute_autos)
408                         autoconf.mute = 1;
409
410
411 // now create a clipboard
412                 file.tag.set_title("AUTO_CLIPBOARD");
413                 file.tag.set_property("LENGTH", 0);
414                 file.tag.set_property("FRAMERATE", edl->session->frame_rate);
415                 file.tag.set_property("SAMPLERATE", edl->session->sample_rate);
416                 file.append_tag();
417                 file.append_newline();
418                 file.append_newline();
419
420 /*              track->copy_automation(position,
421                         position,
422                         &file,
423                         0,
424                         0);
425                         */
426                 file.tag.set_title("TRACK");
427 // Video or audio
428                 track->save_header(&file);
429                 file.append_tag();
430                 file.append_newline();
431
432                 track->automation->copy(position,
433                         position,
434                         &file,
435                         0,
436                         0,
437                         &autoconf);
438                 file.tag.set_title("/TRACK");
439                 file.append_tag();
440                 file.append_newline();
441                 file.append_newline();
442                 file.append_newline();
443                 file.append_newline();
444
445                 file.tag.set_title("/AUTO_CLIPBOARD");
446                 file.append_tag();
447                 file.append_newline();
448                 file.terminate_string();
449
450                 mwindow->gui->lock_window();
451                 mwindow->gui->to_clipboard(file.string, strlen(file.string), SECONDARY_SELECTION);
452                 mwindow->gui->unlock_window();
453
454         } else
455 #endif
456                 mwindow->copy_automation();
457         return 1;
458 }
459
460
461
462 KeyframePopupCurveMode::KeyframePopupCurveMode(
463         MWindow *mwindow,
464         KeyframePopup *popup,
465         int curve_mode)
466  : BC_MenuItem( get_labeltext(curve_mode))
467 {
468         this->curve_mode = curve_mode;
469         this->mwindow = mwindow;
470         this->popup = popup;
471 }
472
473 KeyframePopupCurveMode::~KeyframePopupCurveMode() { }
474
475
476 const char *KeyframePopupCurveMode::get_labeltext(int mode)
477 {
478         switch(mode) {
479         case FloatAuto::SMOOTH: return _("smooth curve");
480         case FloatAuto::LINEAR: return _("linear segments");
481         case FloatAuto::TFREE:  return _("tangent edit");
482         case FloatAuto::FREE:   return _("disjoint edit");
483         case FloatAuto::BUMP:   return _("bump edit");
484         }
485         return _("misconfigured");
486 }
487
488
489 void KeyframePopupCurveMode::toggle_mode(FloatAuto *keyframe)
490 {
491         set_checked(curve_mode == keyframe->curve_mode);
492 }
493
494
495 int KeyframePopupCurveMode::handle_event()
496 {
497         if (popup->keyframe_autos &&
498             popup->keyframe_autos->get_type() == AUTOMATION_TYPE_FLOAT)
499         {
500                 mwindow->undo->update_undo_before(_("change keyframe curve mode"), 0);
501                 ((FloatAuto*)popup->keyframe_auto)->
502                         change_curve_mode((FloatAuto::t_mode)curve_mode);
503
504                 // if we switched to some "auto" mode, this may imply a
505                 // real change to parameters, so this needs to be undoable...
506                 mwindow->undo->update_undo_after(_("change keyframe curve mode"), LOAD_ALL);
507                 mwindow->save_backup();
508
509                 mwindow->gui->update(0, NORMAL_DRAW, 0,0,0,0,0); // incremental redraw for canvas
510                 mwindow->cwindow->update(0,0, 1, 0,0); // redraw tool window in compositor
511                 mwindow->update_plugin_guis();
512                 mwindow->restart_brender();
513                 mwindow->sync_parameters(CHANGE_EDL);
514         }
515         return 1;
516 }
517
518
519 KeyframePopupEdit::KeyframePopupEdit(MWindow *mwindow, KeyframePopup *popup)
520  : BC_MenuItem(_("Edit Params..."))
521 {
522         this->mwindow = mwindow;
523         this->popup = popup;
524 }
525
526 int KeyframePopupEdit::handle_event()
527 {
528         mwindow->show_keyframe_gui(popup->keyframe_plugin);
529         return 1;
530 }
531
532
533 KeyframeHidePopup::KeyframeHidePopup(MWindow *mwindow, MWindowGUI *gui)
534  : BC_PopupMenu(0, 0, 0, "", 0)
535 {
536         this->mwindow = mwindow;
537         this->gui = gui;
538         this->keyframe_autos = 0;
539 }
540
541 KeyframeHidePopup::~KeyframeHidePopup()
542 {
543 }
544
545 void KeyframeHidePopup::create_objects()
546 {
547         add_item(new KeyframeHideItem(mwindow, this));
548 }
549
550 int KeyframeHidePopup::update(Autos *autos)
551 {
552         this->keyframe_autos = autos;
553         return 0;
554 }
555
556 KeyframeHideItem::KeyframeHideItem(MWindow *mwindow, KeyframeHidePopup *popup)
557  : BC_MenuItem(_("Hide keyframe type"))
558 {
559         this->mwindow = mwindow;
560         this->popup = popup;
561 }
562
563
564 int KeyframeHideItem::handle_event()
565 {
566         if( popup->keyframe_autos )
567                 mwindow->set_auto_visibility(popup->keyframe_autos, 0);
568         return 1;
569 }
570
571
572
573 KeyMutePatch::KeyMutePatch(MWindow *mwindow, PatchGUI *patch, int x, int y)
574  : BC_SubWindow(x, y, 100, 20, GWindowGUI::auto_colors[AUTOMATION_MUTE])
575 {
576         this->mwindow = mwindow;
577         this->patch = patch;
578 }
579
580 void KeyMutePatch::create_objects()
581 {
582         key_mute_checkbox = new KeyMuteValue(this);
583         add_subwindow(key_mute_checkbox);
584         key_mute_checkbox->activate();
585         show_window();
586 }
587
588 KeyMuteValue::KeyMuteValue(KeyMutePatch *key_mute_patch)
589  : BC_CheckBox(0,0, key_mute_patch->mwindow->
590         get_int_auto(key_mute_patch->patch, AUTOMATION_MUTE)->value,
591         _("Mute"), MEDIUMFONT, RED)
592 {
593         this->key_mute_patch = key_mute_patch;
594 }
595
596 int KeyMuteValue::button_release_event()
597 {
598         BC_CheckBox::button_release_event();
599         key_mute_patch->mwindow->gui->close_keyvalue_popup();
600         return 1;
601 }
602
603 int KeyMuteValue::handle_event()
604 {
605         MWindow *mwindow = key_mute_patch->mwindow;
606         PatchGUI *patch = key_mute_patch->patch;
607
608         patch->change_source = 1;
609         double position = mwindow->edl->local_session->get_selectionstart(1);
610         Autos *mute_autos = patch->track->automation->autos[AUTOMATION_MUTE];
611         int need_undo = !mute_autos->auto_exists_for_editing(position);
612         mwindow->undo->update_undo_before(_("mute"), need_undo ? 0 : this);
613         IntAuto *current = (IntAuto*)mute_autos->get_auto_for_editing(position);
614         current->value = this->get_value();
615         mwindow->undo->update_undo_after(_("mute"), LOAD_AUTOMATION);
616         patch->change_source = 0;
617
618         mwindow->sync_parameters(CHANGE_PARAMS);
619         if( mwindow->edl->session->auto_conf->autos[AUTOMATION_MUTE] ) {
620                 mwindow->gui->update_patchbay();
621                 mwindow->gui->draw_overlays(1);
622         }
623         return 1;
624 }
625
626 KeySpeedPatch::KeySpeedPatch(MWindow *mwindow, PatchGUI *gui,
627                 int bump, int x, int y)
628  : BC_SubWindow(x,y, xS(200)+4, yS(bump ? 50 : 24)+4,
629                 GWindowGUI::auto_colors[AUTOMATION_SPEED])
630 {
631         this->mwindow = mwindow;
632         this->gui = gui;
633         need_undo = 1;
634 }
635 KeySpeedPatch::~KeySpeedPatch()
636 {
637 }
638
639 void KeySpeedPatch::create_objects()
640 {
641         int x = 2, x1 = x, y = 2, dy = 0;
642         FloatAuto *speed_auto = mwindow->get_float_auto(gui, AUTOMATION_SPEED);
643         float v = speed_auto->get_value(gui->edge);
644         add_subwindow(key_speed_text = new KeySpeedText(this, x, y, xS(64), v));
645         x += key_speed_text->get_w();
646         dy = bmax(dy, key_speed_text->get_h());
647         VFrame **lok_images = mwindow->theme->get_image_set("lok");
648         int w1 = get_w()-2 - x - lok_images[0]->get_w();
649         add_subwindow(key_speed_slider = new KeySpeedSlider(this, x, y, w1, v));
650         x += key_speed_slider->get_w();
651         dy = bmax(dy, key_speed_slider->get_h());
652         add_subwindow(key_speed_ok = new KeySpeedOK(this, x, y, lok_images));
653         dy = bmax(dy, key_speed_ok->get_h());
654         if( speed_auto->is_bump() ) {
655                 y += dy;
656                 set_color(get_resources()->get_bg_color());
657                 draw_box(0,y, get_w(),get_h());
658                 add_subwindow(auto_edge = new KeySpeedAutoEdge(mwindow, this, x1, y));
659                 x1 += auto_edge->get_w() + xS(15);
660                 add_subwindow(auto_span = new KeySpeedAutoSpan(mwindow, this, x1, y));
661         }
662         draw_3d_border(0,0, get_w(), get_h(), 0);
663         activate();
664         show_window();
665         mwindow->speed_before();
666 }
667
668 void KeySpeedPatch::set_edge(int edge)
669 {
670         gui->edge = edge;
671         FloatAuto *speed_auto = mwindow->get_float_auto(gui, AUTOMATION_SPEED);
672         float v = speed_auto->get_value(edge);
673         update(v);
674 }
675
676 void KeySpeedPatch::set_span(int span)
677 {
678         gui->span = span;
679 }
680
681 void KeySpeedPatch::update(float v)
682 {
683         key_speed_text->update(v);
684         key_speed_slider->update(v);
685         update_speed(v);
686 }
687
688 void KeySpeedPatch::update_speed(float v)
689 {
690         Track *track = gui->track;
691         if( !track->is_armed() ) return;
692         Autos *speed_autos = track->automation->autos[AUTOMATION_SPEED];
693         double position = mwindow->edl->local_session->get_selectionstart(1);
694         FloatAuto *current = (FloatAuto*)speed_autos->get_auto_for_editing(position);
695         float change = v - current->get_value(gui->edge);
696         if( !change ) return;
697         gui->change_source = 1;
698         if( need_undo ) {
699                 need_undo = 0;
700                 mwindow->undo->update_undo_before(_("speed"), this);
701         }
702         current->bump_value(v, gui->edge, gui->span);
703         if( track->is_ganged() ) {
704                 TrackCanvas *track_canvas = gui->patchbay->pane->canvas;
705                 track_canvas->fill_ganged_autos(-1, change, track, current);
706                 track_canvas->update_ganged_autos(0, track, current);
707                 track_canvas->clear_ganged_autos();
708         }
709         gui->change_source = 0;
710
711         mwindow->sync_parameters(CHANGE_PARAMS);
712         if(mwindow->edl->session->auto_conf->autos[AUTOMATION_SPEED]) {
713                 mwindow->gui->draw_overlays(1);
714         }
715 }
716
717 KeySpeedOK::KeySpeedOK(KeySpeedPatch *key_speed_patch, int x, int y, VFrame **images)
718  : BC_Button(x, y, images)
719 {
720         this->key_speed_patch = key_speed_patch;
721 }
722
723 int KeySpeedOK::handle_event()
724 {
725         MWindow *mwindow = key_speed_patch->mwindow;
726         mwindow->speed_after(1, 1);
727         if( !key_speed_patch->need_undo ) {
728                 mwindow->undo->update_undo_after(_("speed"),
729                         LOAD_AUTOMATION + LOAD_EDITS + LOAD_TIMEBAR);
730         }
731         mwindow->resync_guis();
732         mwindow->gui->close_keyvalue_popup();
733         return 1;
734 }
735
736 KeySpeedText::KeySpeedText(KeySpeedPatch *key_speed_patch, int x, int y, int w, float v)
737  : BC_TextBox(x, y, w, 1, v, 1, MEDIUMFONT, 2)
738 {
739         this->key_speed_patch = key_speed_patch;
740 }
741
742 int KeySpeedText::handle_event()
743 {
744         float v = atof(get_text());
745         key_speed_patch->update(v);
746         return get_keypress() != RETURN ? 1 :
747                 key_speed_patch->key_speed_ok->handle_event();
748 }
749
750 KeySpeedSlider::KeySpeedSlider(KeySpeedPatch *key_speed_patch,
751                 int x, int y, int w, float v)
752  : BC_FSlider(x, y, 0, w, w,
753         key_speed_patch->mwindow->edl->local_session->automation_mins[AUTOGROUPTYPE_SPEED],
754         key_speed_patch->mwindow->edl->local_session->automation_maxs[AUTOGROUPTYPE_SPEED],
755         v)
756 {
757         this->key_speed_patch = key_speed_patch;
758         key_speed_patch->mwindow->speed_before();
759         set_precision(0.01);
760 }
761
762 KeySpeedSlider::~KeySpeedSlider()
763 {
764 }
765
766 int KeySpeedSlider::handle_event()
767 {
768         if( shift_down() ) {
769                 update(1.0);
770                 set_tooltip(get_caption());
771         }
772         key_speed_patch->update(get_value());
773         return 1;
774 }
775
776 KeySpeedAutoEdge::KeySpeedAutoEdge(MWindow *mwindow,
777                 KeySpeedPatch *patch, int x, int y)
778  : BC_Toggle(x, y, mwindow->theme->get_image_set("bump_edge"),
779                 patch->gui->edge,_("Edge"))
780 {
781         this->mwindow = mwindow;
782         this->patch = patch;
783         set_tooltip(_("Bump uses left edge"));
784 }
785
786 int KeySpeedAutoEdge::handle_event()
787 {
788         patch->set_edge(get_value());
789         return 1;
790 }
791
792 KeySpeedAutoSpan::KeySpeedAutoSpan(MWindow *mwindow,
793                 KeySpeedPatch *patch, int x, int y)
794  : BC_Toggle(x, y, mwindow->theme->get_image_set("bump_span"),
795                 patch->gui->span,_("Span"))
796 {
797         this->mwindow = mwindow;
798         this->patch = patch;
799         set_tooltip(_("Bump spans to next"));
800 }
801
802 int KeySpeedAutoSpan::handle_event()
803
804 {
805         patch->set_span(get_value());
806         return 1;
807 }
808