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