
/*
 * CINELERRA
 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
 * Copyright (C) 2003-2016 Cinelerra CV contributors
 *
 * 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 "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 "localsession.h"
#include "maincursor.h"
#include "mainmenu.h"
#include "mainundo.h"
#include "mwindowgui.h"
#include "mwindow.h"
#include "patchbay.h"
#include "patchgui.h"
#include "theme.h"
#include "timelinepane.h"
#include "track.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;
	key_smooth = 0;
	key_linear = 0;
	key_free = 0;
	key_mbar = 0;
	key_mode_displayed = false;
	key_edit_displayed = false;
	popx = popy = 0;
}

KeyframePopup::~KeyframePopup()
{
	if( !key_mode_displayed ) {
		delete key_mbar;
		delete key_smooth;
		delete key_linear;
		delete key_free_t;
		delete key_free;
		delete key_bump;
	}
	if( !key_edit_displayed ) {
		delete key_edit;
	}
}

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));

	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  );
	key_bump   = new KeyframePopupCurveMode(mwindow, this, FloatAuto::BUMP  );
}

int KeyframePopup::update(Plugin *plugin, KeyFrame *keyframe)
{
	gui->get_relative_cursor(popx, popy);
	key_show->set_text(_("Show Plugin Settings"));
	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)
{
	gui->get_relative_cursor(popx, popy);
	key_show->set_text(_(GWindowGUI::auto_text[autos->autoidx]));
	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, NORMAL_DRAW, 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
{
	deactivate();
	if( !key_edit_displayed && keyframe_plugin ) {
		add_item(key_edit);
		key_edit_displayed = true;
	}
	else if( key_edit_displayed && !keyframe_plugin ) {
		remove_item(key_edit);
		key_edit_displayed = false;
	}

	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);
		add_item(key_bump);
		key_mode_displayed = true;
	}
	else if(key_mode_displayed && (!autos || autos->get_type() != AUTOMATION_TYPE_FLOAT))
	{ // remove additional menu entries
		remove_item(key_bump);
		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);
		key_bump  ->toggle_mode((FloatAuto*)auto_keyframe);
	}
	activate();
}

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);
	mwindow->speed_before();
	delete popup->keyframe_auto;
	mwindow->speed_after(1, 1);
	mwindow->undo->update_undo_after(_("delete keyframe"), LOAD_ALL);

	mwindow->save_backup();
	mwindow->gui->update(0, NORMAL_DRAW,
		0, 0, 0, 0, 0);
	mwindow->update_plugin_guis();
	mwindow->restart_brender();
	mwindow->sync_parameters(CHANGE_EDL);

	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"))
{
	this->mwindow = mwindow;
	this->popup = popup;
}

KeyframePopupShow::~KeyframePopupShow()
{
}

int KeyframePopupShow::handle_event()
{
	MWindowGUI *mgui = mwindow->gui;
	CWindowGUI *cgui = mwindow->cwindow->gui;
	int cx = popup->popx, cy = popup->popy;
	int xmargin = mgui->get_w() - xS(200);
	int ymargin = mgui->get_h() - yS(50);
	if( cx > xmargin ) cx = xmargin;
	if( cy > ymargin ) cy = ymargin;
	xmargin = xS(15);  ymargin = yS(15);
	if( cx < xmargin ) cx = xmargin;
	if( cy < ymargin ) cy = ymargin;
	mgui->close_keyvalue_popup();

	if( popup->keyframe_plugin ) {
		mwindow->update_plugin_guis();
		mwindow->show_plugin(popup->keyframe_plugin);
	}
	else if( popup->keyframe_automation ) {
		cgui->lock_window();
		int show_window = 1;

		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;
			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->open_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->open_keyvalue_popup(pan);
			break; }

			case AUTOMATION_FADE: {
				FloatAuto *fade_auto = mwindow->get_float_auto(patchgui, AUTOMATION_FADE);
				int bump = fade_auto->is_bump();
				switch( patchgui->data_type ) {
				case TRACK_AUDIO: {
					AKeyFadePatch *fade = new AKeyFadePatch(mwindow,
							(APatchGUI *)patchgui, bump, cx, cy);
					mgui->add_subwindow(fade);
					fade->create_objects();
					mgui->open_keyvalue_popup(fade);
					break; }
				case TRACK_VIDEO: {
					VKeyFadePatch *fade = new VKeyFadePatch(mwindow,
							(VPatchGUI *)patchgui, bump, cx, cy);
					mgui->add_subwindow(fade);
					fade->create_objects();
					mgui->open_keyvalue_popup(fade);
					break; }
				}
				break; }

			case AUTOMATION_SPEED: {
				FloatAuto *speed_auto = mwindow->get_float_auto(patchgui, AUTOMATION_SPEED);
				int bump = speed_auto->is_bump();
				KeySpeedPatch *speed = new KeySpeedPatch(mwindow, patchgui, bump, cx, cy);
				mgui->add_subwindow(speed);
				speed->create_objects();
				mgui->open_keyvalue_popup(speed);
				break; }

			case AUTOMATION_MUTE: {
				KeyMutePatch *mute = new KeyMutePatch(mwindow, (APatchGUI *)patchgui, cx, cy);
				mgui->add_subwindow(mute);
				mute->create_objects();
				mgui->open_keyvalue_popup(mute);
				break; }
			}
			break; }
		}

// ensure bringing to front
		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);
		}
		cgui->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->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");
	case FloatAuto::BUMP:   return _("bump 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, NORMAL_DRAW, 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;
}


KeyframeHidePopup::KeyframeHidePopup(MWindow *mwindow, MWindowGUI *gui)
 : BC_PopupMenu(0, 0, 0, "", 0)
{
	this->mwindow = mwindow;
	this->gui = gui;
	this->keyframe_autos = 0;
}

KeyframeHidePopup::~KeyframeHidePopup()
{
}

void KeyframeHidePopup::create_objects()
{
	add_item(new KeyframeHideItem(mwindow, this));
}

int KeyframeHidePopup::update(Autos *autos)
{
	this->keyframe_autos = autos;
	return 0;
}

KeyframeHideItem::KeyframeHideItem(MWindow *mwindow, KeyframeHidePopup *popup)
 : BC_MenuItem(_("Hide keyframe type"))
{
	this->mwindow = mwindow;
	this->popup = popup;
}


int KeyframeHideItem::handle_event()
{
	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();
	key_mute_patch->mwindow->gui->close_keyvalue_popup();
	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;
}

KeySpeedPatch::KeySpeedPatch(MWindow *mwindow, PatchGUI *gui,
		int bump, int x, int y)
 : BC_SubWindow(x,y, xS(200)+4, yS(bump ? 50 : 24)+4,
		GWindowGUI::auto_colors[AUTOMATION_SPEED])
{
	this->mwindow = mwindow;
	this->gui = gui;
	need_undo = 1;
}
KeySpeedPatch::~KeySpeedPatch()
{
}

void KeySpeedPatch::create_objects()
{
	int x = 2, x1 = x, y = 2, dy = 0;
	FloatAuto *speed_auto = mwindow->get_float_auto(gui, AUTOMATION_SPEED);
	float v = speed_auto->get_value(gui->edge);
	add_subwindow(key_speed_text = new KeySpeedText(this, x, y, xS(64), v));
	x += key_speed_text->get_w();
	dy = bmax(dy, key_speed_text->get_h());
	VFrame **lok_images = mwindow->theme->get_image_set("lok");
	int w1 = get_w()-2 - x - lok_images[0]->get_w();
	add_subwindow(key_speed_slider = new KeySpeedSlider(this, x, y, w1, v));
	x += key_speed_slider->get_w();
	dy = bmax(dy, key_speed_slider->get_h());
	add_subwindow(key_speed_ok = new KeySpeedOK(this, x, y, lok_images));
	dy = bmax(dy, key_speed_ok->get_h());
	if( speed_auto->is_bump() ) {
		y += dy;
		set_color(get_resources()->get_bg_color());
		draw_box(0,y, get_w(),get_h());
		add_subwindow(auto_edge = new KeySpeedAutoEdge(mwindow, this, x1, y));
		x1 += auto_edge->get_w() + xS(15);
		add_subwindow(auto_span = new KeySpeedAutoSpan(mwindow, this, x1, y));
	}
	draw_3d_border(0,0, get_w(), get_h(), 0);
	activate();
	show_window();
	mwindow->speed_before();
}

void KeySpeedPatch::set_edge(int edge)
{
	gui->edge = edge;
	FloatAuto *speed_auto = mwindow->get_float_auto(gui, AUTOMATION_SPEED);
	float v = speed_auto->get_value(edge);
	update(v);
}

void KeySpeedPatch::set_span(int span)
{
	gui->span = span;
}

void KeySpeedPatch::update(float v)
{
	key_speed_text->update(v);
	key_speed_slider->update(v);
	update_speed(v);
}

void KeySpeedPatch::update_speed(float v)
{
	Track *track = gui->track;
	if( !track->is_armed() ) return;
	Autos *speed_autos = track->automation->autos[AUTOMATION_SPEED];
	double position = mwindow->edl->local_session->get_selectionstart(1);
	FloatAuto *current = (FloatAuto*)speed_autos->get_auto_for_editing(position);
	float change = v - current->get_value(gui->edge);
	if( !change ) return;
	gui->change_source = 1;
	if( need_undo ) {
		need_undo = 0;
		mwindow->undo->update_undo_before(_("speed"), this);
	}
	current->bump_value(v, gui->edge, gui->span);
	if( track->is_ganged() ) {
		TrackCanvas *track_canvas = gui->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();
	}
	gui->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, 1);
	if( !key_speed_patch->need_undo ) {
		mwindow->undo->update_undo_after(_("speed"),
			LOAD_AUTOMATION + LOAD_EDITS + LOAD_TIMEBAR);
	}
	mwindow->resync_guis();
	mwindow->gui->close_keyvalue_popup();
	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;
}

KeySpeedAutoEdge::KeySpeedAutoEdge(MWindow *mwindow,
		KeySpeedPatch *patch, int x, int y)
 : BC_Toggle(x, y, mwindow->theme->get_image_set("bump_edge"),
                patch->gui->edge,_("Edge"))
{
	this->mwindow = mwindow;
	this->patch = patch;
	set_tooltip(_("Bump uses left edge"));
}

int KeySpeedAutoEdge::handle_event()
{
	patch->set_edge(get_value());
	return 1;
}

KeySpeedAutoSpan::KeySpeedAutoSpan(MWindow *mwindow,
		KeySpeedPatch *patch, int x, int y)
 : BC_Toggle(x, y, mwindow->theme->get_image_set("bump_span"),
                patch->gui->span,_("Span"))
{
	this->mwindow = mwindow;
	this->patch = patch;
	set_tooltip(_("Bump spans to next"));
}

int KeySpeedAutoSpan::handle_event()

{
	patch->set_span(get_value());
	return 1;
}

