4 * Copyright (C) 2017 Adam Williams <broadcast at earthling dot net>
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.
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.
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
23 #include "bcsignals.h"
26 #include "filesystem.h"
28 #include "keyframes.h"
29 #include "keyframegui.h"
32 #include "localsession.h"
33 #include "mainsession.h"
36 #include "mwindowgui.h"
38 #include "preferences.h"
41 #include "trackcanvas.h"
45 KeyFrameThread::KeyFrameThread(MWindow *mwindow)
48 this->mwindow = mwindow;
51 keyframe_data = new ArrayList<BC_ListBoxItem*>[KEYFRAME_COLUMNS];
56 column_titles[0] = (char*)_("Parameter");
57 column_titles[1] = (char*)_("Value");
60 presets_data = new ArrayList<BC_ListBoxItem*>;
61 presets_db = new PresetsDB;
64 KeyFrameThread::~KeyFrameThread()
66 for( int i=0; i<KEYFRAME_COLUMNS; ++i )
67 keyframe_data[i].remove_all_objects();
68 delete [] keyframe_data;
69 presets_data->remove_all_objects();
71 is_factories.remove_all();
72 preset_titles.remove_all_objects();
78 void KeyFrameThread::update_values()
80 // Get the current selection before deleting the tables
82 for( int i=0; i<keyframe_data[0].size(); ++i ) {
83 if( keyframe_data[0].get(i)->get_selected() ) {
89 for( int i=0; i<KEYFRAME_COLUMNS; ++i )
90 keyframe_data[i].remove_all_objects();
93 // Must lock main window to read keyframe
94 mwindow->gui->lock_window("KeyFrameThread::update_values");
95 Plugin *plugin = mwindow->edl->tracks->plugin_exists(plugin_id);
97 mwindow->gui->unlock_window();
101 KeyFrame *keyframe = 0;
102 if( this->keyframe && plugin->keyframe_exists(this->keyframe) ) {
103 // If user edited a specific keyframe, use it.
104 keyframe = this->keyframe;
107 if( plugin->track ) {
108 // Use currently highlighted keyframe
109 keyframe = plugin->get_prev_keyframe(
110 plugin->track->to_units(
111 mwindow->edl->local_session->get_selectionstart(1), 0),
117 char *text = 0, *data = 0;
118 keyframe->get_contents(&hash, &text, &data);
120 for( int i=0; i<hash.size(); ++i ) {
121 keyframe_data[0].append(new BC_ListBoxItem(hash.get_key(i)));
122 keyframe_data[1].append(new BC_ListBoxItem(hash.get_value(i)));
125 keyframe_data[0].append(new BC_ListBoxItem((char*)"TEXT"));
126 keyframe_data[1].append(new BC_ListBoxItem(text));
129 keyframe_data[0].append(new BC_ListBoxItem((char*)"DATA"));
130 keyframe_data[1].append(new BC_ListBoxItem(data));
136 column_width[0] = mwindow->session->keyframedialog_column1;
137 column_width[1] = mwindow->session->keyframedialog_column2;
138 if( selection >= 0 && selection < keyframe_data[0].size() ) {
139 for( int i=0; i<KEYFRAME_COLUMNS; ++i )
140 keyframe_data[i].get(selection)->set_selected(1);
142 mwindow->gui->unlock_window();
147 void KeyFrameThread::start_window(Plugin *plugin, KeyFrame *keyframe)
150 if( !BC_DialogThread::is_running() ) {
151 if( !mwindow->edl->tracks->plugin_exists(plugin->orig_id) ) return;
152 this->keyframe = keyframe;
153 this->plugin_id = plugin->orig_id;
154 this->preset_text[0] = 0;
155 plugin->calculate_title(plugin_title, 0);
156 sprintf(window_title, _("%s: %s Keyframe"), _(PROGRAM_NAME), plugin_title);
158 // Load all the presets from disk
159 char path[BCTEXTLEN];
161 // system wide presets
162 sprintf(path, "%s/%s", File::get_cindat_path(), FACTORY_FILE);
163 fs.complete_path(path);
164 presets_db->load_from_file(path, 1, 1);
166 sprintf(path, "%s/%s", File::get_config_path(), PRESETS_FILE);
167 fs.complete_path(path);
168 presets_db->load_from_file(path, 0, 0);
170 calculate_preset_list();
175 mwindow->gui->unlock_window();
176 BC_DialogThread::start();
177 mwindow->gui->lock_window("KeyFrameThread::start_window");
180 BC_DialogThread::start();
184 BC_Window* KeyFrameThread::new_gui()
186 mwindow->gui->lock_window("KeyFrameThread::new_gui");
188 int x = mwindow->gui->get_abs_cursor_x(0) -
189 mwindow->session->plugindialog_w / 2;
190 int y = mwindow->gui->get_abs_cursor_y(0) -
191 mwindow->session->plugindialog_h / 2;
193 KeyFrameWindow *window = new KeyFrameWindow(mwindow,
199 window->create_objects();
202 mwindow->gui->unlock_window();
207 void KeyFrameThread::handle_done_event(int result)
211 get_gui()->lock_window("KeyFrameThread::handle_done_event");
212 apply_preset(preset_text, is_factory);
213 get_gui()->unlock_window();
217 void KeyFrameThread::handle_close_event(int result)
223 void KeyFrameThread::close_window()
225 lock_dialog("KeyFrameThread::close_window");
227 get_gui()->lock_window("KeyFrameThread::close_window");
228 get_gui()->set_done(1);
229 get_gui()->unlock_window();
236 void KeyFrameThread::calculate_preset_list()
238 presets_data->remove_all_objects();
239 is_factories.remove_all();
240 preset_titles.remove_all_objects();
241 int total_presets = presets_db->get_total_presets(plugin_title, 0);
244 presets_db->sort(plugin_title);
246 for( int i=0; i<total_presets; ++i ) {
247 char text[BCTEXTLEN];
248 char *orig_title = presets_db->get_preset_title( plugin_title, i);
249 if( !orig_title ) continue;
250 int is_factory = presets_db->get_is_factory(plugin_title, i);
251 sprintf(text, "%s%s", is_factory ? "*" : "", orig_title);
252 presets_data->append(new BC_ListBoxItem(text));
254 preset_titles.append(strdup(orig_title));
255 is_factories.append(is_factory);
260 void KeyFrameThread::update_gui(int update_value_text)
263 if( BC_DialogThread::is_running() ) {
264 mwindow->gui->lock_window("KeyFrameThread::update_gui");
266 mwindow->gui->unlock_window();
268 lock_dialog("KeyFrameThread::update_gui");
269 KeyFrameWindow *window = (KeyFrameWindow*)get_gui();
271 window->lock_window("KeyFrameThread::update_gui");
272 window->keyframe_list->update(keyframe_data,
276 window->keyframe_list->get_xposition(),
277 window->keyframe_list->get_yposition(),
278 window->keyframe_list->get_highlighted_item());
279 if( update_value_text &&
280 window->keyframe_list->get_selection_number(0, 0) >= 0 &&
281 window->keyframe_list->get_selection_number(0, 0) < keyframe_data[1].size() ) {
282 window->value_text->update(
283 keyframe_data[1].get(window->keyframe_list->get_selection_number(0, 0))->get_text());
285 window->unlock_window();
292 void KeyFrameThread::save_preset(const char *title, int is_factory)
294 get_gui()->unlock_window();
295 mwindow->gui->lock_window("KeyFrameThread::save_preset");
297 // Test EDL for plugin existence
298 Plugin *plugin = mwindow->edl->tracks->plugin_exists(plugin_id);
300 mwindow->gui->unlock_window();
301 get_gui()->lock_window("KeyFrameThread::save_preset 2");
305 // Get current plugin keyframe
306 EDL *edl = mwindow->edl;
307 Track *track = plugin->track;
308 KeyFrame *keyframe = plugin->get_prev_keyframe(
309 track->to_units(edl->local_session->get_selectionstart(1), 0),
313 presets_db->save_preset(plugin_title, title, keyframe->get_data());
315 mwindow->gui->unlock_window();
316 get_gui()->lock_window("KeyFrameThread::save_preset 2");
319 calculate_preset_list();
320 ((KeyFrameWindow*)get_gui())->preset_list->update(presets_data,
324 void KeyFrameThread::delete_preset(const char *title, int is_factory)
326 get_gui()->unlock_window();
327 mwindow->gui->lock_window("KeyFrameThread::save_preset");
329 // Test EDL for plugin existence
330 Plugin *plugin = mwindow->edl->tracks->plugin_exists(plugin_id);
332 mwindow->gui->unlock_window();
333 get_gui()->lock_window("KeyFrameThread::delete_preset 1");
337 presets_db->delete_preset(plugin_title, title, is_factory);
339 mwindow->gui->unlock_window();
340 get_gui()->lock_window("KeyFrameThread::delete_preset 2");
343 calculate_preset_list();
344 ((KeyFrameWindow*)get_gui())->preset_list->update(presets_data,
349 void KeyFrameThread::apply_preset(const char *title, int is_factory)
351 if( presets_db->preset_exists(plugin_title, title, is_factory) ) {
352 get_gui()->unlock_window();
353 mwindow->gui->lock_window("KeyFrameThread::apply_preset");
355 // Test EDL for plugin existence
356 Plugin *plugin = mwindow->edl->tracks->plugin_exists(plugin_id);
358 mwindow->gui->unlock_window();
359 get_gui()->lock_window("KeyFrameThread::apply_preset 1");
363 mwindow->undo->update_undo_before();
365 #ifdef USE_KEYFRAME_SPANNING
366 ArrayList<PluginServer*> &plugindb = *mwindow->plugindb;
367 int k = plugindb.size();
368 while( --k>=0 && strcmp(plugindb[k]->title, plugin->title) );
370 PluginServer server(*plugindb[k]);
371 server.open_plugin(0, mwindow->preferences, mwindow->edl, plugin);
372 KeyFrame keyframe(mwindow->edl, plugin->keyframes);
373 presets_db->load_preset(plugin_title, title, &keyframe, is_factory);
374 server.apply_keyframe(plugin, &keyframe);
377 KeyFrame *keyframe = plugin->get_keyframe();
378 presets_db->load_preset(plugin_title, title, keyframe, is_factory);
380 mwindow->save_backup();
381 mwindow->undo->update_undo_after(_("apply preset"), LOAD_AUTOMATION);
383 mwindow->update_plugin_guis(0);
384 mwindow->gui->draw_overlays(1);
385 mwindow->sync_parameters(CHANGE_PARAMS);
389 mwindow->gui->unlock_window();
390 get_gui()->lock_window("KeyFrameThread::apply_preset");
396 void KeyFrameThread::apply_value()
398 const char *text = 0, *data = 0;
400 KeyFrameWindow *window = (KeyFrameWindow*)get_gui();
401 int selection = window->keyframe_list->get_selection_number(0, 0);
402 //printf("KeyFrameThread::apply_value %d %d\n", __LINE__, selection);
403 if( selection < 0 ) return;
405 if( selection == keyframe_data[0].size() - 2 )
406 text = window->value_text->get_text();
407 else if( selection == keyframe_data[0].size() - 1 )
408 data = window->value_text->get_text();
410 const char *key = keyframe_data[0].get(selection)->get_text();
411 const char *value = window->value_text->get_text();
412 hash = new BC_Hash();
413 hash->update(key, value);
416 get_gui()->unlock_window();
417 mwindow->gui->lock_window("KeyFrameThread::apply_value");
418 Plugin *plugin = mwindow->edl->tracks->plugin_exists(plugin_id);
420 mwindow->undo->update_undo_before();
421 if( mwindow->session->keyframedialog_all ) {
422 // Search for all keyframes in selection but don't create a new one.
423 Track *track = plugin->track;
424 int64_t start = track->to_units(mwindow->edl->local_session->get_selectionstart(0), 0);
425 int64_t end = track->to_units(mwindow->edl->local_session->get_selectionend(0), 0);
427 KeyFrame *current = (KeyFrame*)plugin->keyframes->last;
428 for( ; current; current=(KeyFrame*)PREVIOUS ) {
430 if( current && current->position < end ) {
431 current->update_parameter(hash, text, data);
432 // Stop at beginning of range
433 if( current->position <= start ) break;
438 current = (KeyFrame*)plugin->keyframes->default_auto;
439 current->update_parameter(hash, text, data);
443 // Create new keyframe if enabled
444 KeyFrame *keyframe = plugin->get_keyframe();
445 keyframe->update_parameter(hash, text, data);
449 printf("KeyFrameThread::apply_value %d: plugin doesn't exist\n", __LINE__);
452 mwindow->save_backup();
453 mwindow->undo->update_undo_after(_("edit keyframe"), LOAD_AUTOMATION);
455 mwindow->update_plugin_guis(0);
456 mwindow->gui->draw_overlays(1);
457 mwindow->sync_parameters(CHANGE_PARAMS);
458 mwindow->gui->unlock_window();
462 get_gui()->lock_window("KeyFrameThread::apply_value");
469 KeyFrameWindow::KeyFrameWindow(MWindow *mwindow, KeyFrameThread *thread,
470 int x, int y, char *title_string)
471 : BC_Window(title_string, x, y,
472 mwindow->session->keyframedialog_w,
473 mwindow->session->keyframedialog_h,
474 xS(320), yS(240), 1, 0, 1)
476 this->mwindow = mwindow;
477 this->thread = thread;
478 // *** CONTEXT_HELP ***
479 context_help_set_keyword("Saved Plugin Presets");
482 void KeyFrameWindow::create_objects()
484 Theme *theme = mwindow->theme;
486 theme->get_keyframedialog_sizes(this);
487 thread->column_width[0] = mwindow->session->keyframedialog_column1;
488 thread->column_width[1] = mwindow->session->keyframedialog_column2;
489 lock_window("KeyFrameWindow::create_objects");
493 int ky = theme->keyframe_list_y - theme->widget_border -
494 BC_Title::calculate_h(this, (char*)"Py", LARGEFONT);
495 add_subwindow(title1 = new BC_Title(theme->keyframe_list_x, ky,
496 _("Keyframe parameters:"), LARGEFONT));
497 add_subwindow(keyframe_list = new KeyFrameList(thread, this,
498 theme->keyframe_list_x, theme->keyframe_list_y,
499 theme->keyframe_list_w, theme->keyframe_list_h));
500 // add_subwindow(title2 = new BC_Title(theme->keyframe_text_x,
501 // theme->keyframe_text_y - theme->widget_border -
502 // BC_Title::calculate_h(this, "P"), _("Global Text:")));
503 // add_subwindow(keyframe_text = new KeyFrameText(thread, this,
504 // theme->keyframe_text_x, theme->keyframe_text_y,
505 // theme->keyframe_text_w));
506 int ey = theme->keyframe_value_y - theme->widget_border -
507 BC_Title::calculate_h(this, "P");
508 add_subwindow(title3 = new BC_Title(theme->keyframe_value_x, ey,
510 add_subwindow(value_text = new KeyFrameValue(thread, this,
511 theme->keyframe_value_x, theme->keyframe_value_y, theme->keyframe_value_w));
512 add_subwindow(all_toggle = new KeyFrameAll(thread, this,
513 theme->keyframe_all_x, theme->keyframe_all_y));
516 int ty = theme->presets_list_y - theme->widget_border -
517 BC_Title::calculate_h(this, (char*)"Py", LARGEFONT);
518 add_subwindow(title4 = new BC_Title(theme->presets_list_x, ty,
519 _("Presets:"), LARGEFONT));
520 add_subwindow(preset_list = new KeyFramePresetsList(thread, this,
521 theme->presets_list_x, theme->presets_list_y,
522 theme->presets_list_w, theme->presets_list_h));
523 int py = theme->presets_text_y - theme->widget_border -
524 BC_Title::calculate_h(this, "Py");
525 add_subwindow(title5 = new BC_Title(theme->presets_text_x, py,
526 _("Preset title:")));
527 add_subwindow(preset_text = new KeyFramePresetsText(thread, this,
528 theme->presets_text_x, theme->presets_text_y, theme->presets_text_w));
529 add_subwindow(delete_preset = new KeyFramePresetsDelete(thread, this,
530 theme->presets_delete_x, theme->presets_delete_y));
531 add_subwindow(save_preset = new KeyFramePresetsSave(thread, this,
532 theme->presets_save_x, theme->presets_save_y));
533 add_subwindow(apply_preset = new KeyFramePresetsApply(thread, this,
534 theme->presets_apply_x, theme->presets_apply_y));
536 add_subwindow(new KeyFramePresetsOK(thread, this));
537 add_subwindow(new BC_CancelButton(this));
543 // called when going in & out of a factory preset
544 void KeyFrameWindow::update_editing()
546 if( thread->is_factory ) {
547 delete_preset->disable();
548 save_preset->disable();
551 delete_preset->enable();
552 save_preset->enable();
556 int KeyFrameWindow::resize_event(int w, int h)
558 Theme *theme = mwindow->theme;
559 mwindow->session->keyframedialog_w = w;
560 mwindow->session->keyframedialog_h = h;
561 theme->get_keyframedialog_sizes(this);
564 int ky = theme->keyframe_list_y - theme->widget_border -
565 BC_Title::calculate_h(this, (char*)"Py", LARGEFONT);
566 title1->reposition_window(theme->keyframe_list_x, ky);
567 // title2->reposition_window(theme->keyframe_text_x,
568 // theme->keyframe_text_y - theme->widget_border -;
569 // BC_Title::calculate_h(this, (char*)"P"));
570 int ey = theme->keyframe_value_y - theme->widget_border -
571 BC_Title::calculate_h(this, "P");
572 title3->reposition_window(theme->keyframe_value_x, ey);
573 keyframe_list->reposition_window(theme->keyframe_list_x, theme->keyframe_list_y,
574 theme->keyframe_list_w, theme->keyframe_list_h);
575 // text->reposition_window(theme->keyframe_text_x, theme->keyframe_text_y,
576 // theme->keyframe_text_w);
577 value_text->reposition_window(theme->keyframe_value_x,
578 theme->keyframe_value_y,
579 theme->keyframe_value_w);
580 all_toggle->reposition_window(theme->keyframe_all_x,
581 theme->keyframe_all_y);
583 int ty = theme->presets_list_y - theme->widget_border -
584 BC_Title::calculate_h(this, (char*)"Py", LARGEFONT);
585 title4->reposition_window(theme->presets_list_x, ty);
586 int py = theme->presets_text_y - theme->widget_border -
587 BC_Title::calculate_h(this, "Py");
588 title5->reposition_window(theme->presets_text_x, py);
591 preset_list->reposition_window(theme->presets_list_x,
592 theme->presets_list_y,
593 theme->presets_list_w,
594 theme->presets_list_h);
595 preset_text->reposition_window(theme->presets_text_x,
596 theme->presets_text_y,
597 theme->presets_text_w);
598 delete_preset->reposition_window(theme->presets_delete_x,
599 theme->presets_delete_y);
600 save_preset->reposition_window(theme->presets_save_x,
601 theme->presets_save_y);
602 apply_preset->reposition_window(theme->presets_apply_x,
603 theme->presets_apply_y);
613 KeyFrameList::KeyFrameList(KeyFrameThread *thread,
614 KeyFrameWindow *window, int x, int y, int w, int h)
615 : BC_ListBox(x, y, w, h, LISTBOX_TEXT, thread->keyframe_data,
616 thread->column_titles, thread->column_width, KEYFRAME_COLUMNS)
618 this->thread = thread;
619 this->window = window;
620 set_master_column(1, 0);
623 int KeyFrameList::selection_changed()
625 window->value_text->update(
626 thread->keyframe_data[1].get(get_selection_number(0, 0))->get_text());
630 int KeyFrameList::handle_event()
636 int KeyFrameList::column_resize_event()
638 thread->mwindow->session->keyframedialog_column1 = get_column_width(0);
639 thread->mwindow->session->keyframedialog_column2 = get_column_width(1);
644 // KeyFrameText::KeyFrameText(KeyFrameThread *thread,
645 // KeyFrameWindow *window,
655 // this->thread = thread;
656 // this->window = window;
659 // int KeyFrameText::handle_event()
664 KeyFrameValue::KeyFrameValue(KeyFrameThread *thread,
665 KeyFrameWindow *window,
675 this->thread = thread;
676 this->window = window;
679 int KeyFrameValue::handle_event()
681 thread->apply_value();
685 KeyFrameAll::KeyFrameAll(KeyFrameThread *thread,
686 KeyFrameWindow *window, int x, int y)
688 thread->mwindow->session->keyframedialog_all,
689 _("Apply to all selected keyframes"))
691 this->thread = thread;
692 this->window = window;
695 int KeyFrameAll::handle_event()
697 thread->mwindow->session->keyframedialog_all = get_value();
701 #endif // EDIT_KEYFRAME
704 KeyFramePresetsList::KeyFramePresetsList(KeyFrameThread *thread,
705 KeyFrameWindow *window, int x, int y, int w, int h)
706 : BC_ListBox(x, y, w, h, LISTBOX_TEXT, thread->presets_data)
708 this->thread = thread;
709 this->window = window;
712 int KeyFramePresetsList::selection_changed()
714 int number = get_selection_number(0, 0);
716 strcpy(thread->preset_text, thread->preset_titles.get(number));
717 thread->is_factory = thread->is_factories.get(number);
718 // show title without factory symbol in the textbox
719 window->preset_text->update(
720 thread->presets_data->get(number)->get_text());
721 window->update_editing();
727 int KeyFramePresetsList::handle_event()
729 thread->apply_preset(thread->preset_text, thread->is_factory);
735 KeyFramePresetsText::KeyFramePresetsText(KeyFrameThread *thread,
736 KeyFrameWindow *window, int x, int y, int w)
737 : BC_TextBox(x, y, w, 1, thread->preset_text)
739 this->thread = thread;
740 this->window = window;
743 // user entered a title
744 int KeyFramePresetsText::handle_event()
746 strcpy(thread->preset_text, get_text());
747 // once changed, it's now not a factory preset
748 thread->is_factory = 0;
749 window->update_editing();
754 KeyFramePresetsDelete::KeyFramePresetsDelete(KeyFrameThread *thread,
755 KeyFrameWindow *window,
758 : BC_GenericButton(x, y, _("Delete"))
760 this->thread = thread;
761 this->window = window;
764 int KeyFramePresetsDelete::handle_event()
766 if( !thread->is_factory ) {
767 thread->delete_preset(thread->preset_text, thread->is_factory);
773 KeyFramePresetsSave::KeyFramePresetsSave(KeyFrameThread *thread,
774 KeyFrameWindow *window,
777 : BC_GenericButton(x, y, C_("Save"))
779 this->thread = thread;
780 this->window = window;
783 int KeyFramePresetsSave::handle_event()
785 if( !thread->is_factory ) {
786 thread->save_preset(thread->preset_text, thread->is_factory);
792 KeyFramePresetsApply::KeyFramePresetsApply(KeyFrameThread *thread,
793 KeyFrameWindow *window,
796 : BC_GenericButton(x, y, _("Apply"))
798 this->thread = thread;
799 this->window = window;
802 int KeyFramePresetsApply::handle_event()
804 thread->apply_preset(thread->preset_text, thread->is_factory);
809 KeyFramePresetsOK::KeyFramePresetsOK(KeyFrameThread *thread,
810 KeyFrameWindow *window)
811 : BC_OKButton(window)
813 this->thread = thread;
814 this->window = window;
817 int KeyFramePresetsOK::keypress_event()
819 if( get_keypress() == RETURN ) {
821 if( thread->presets_db->preset_exists(thread->plugin_title,
822 thread->preset_text, thread->is_factory) ) {
827 if( !thread->is_factory ) {
828 thread->save_preset(thread->preset_text, thread->is_factory);
833 return context_help_check_and_show();