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();
77 void KeyFrameThread::update_values()
79 // Get the current selection before deleting the tables
81 for( int i=0; i<keyframe_data[0].size(); ++i ) {
82 if( keyframe_data[0].get(i)->get_selected() ) {
88 for( int i=0; i<KEYFRAME_COLUMNS; ++i )
89 keyframe_data[i].remove_all_objects();
92 // Must lock main window to read keyframe
93 mwindow->gui->lock_window("KeyFrameThread::update_values");
94 if( !plugin || !mwindow->edl->tracks->plugin_exists(plugin) ) {
95 mwindow->gui->unlock_window();
99 KeyFrame *keyframe = 0;
100 if( this->keyframe && plugin->keyframe_exists(this->keyframe) ) {
101 // If user edited a specific keyframe, use it.
102 keyframe = this->keyframe;
105 if( plugin->track ) {
106 // Use currently highlighted keyframe
107 keyframe = plugin->get_prev_keyframe(
108 plugin->track->to_units(
109 mwindow->edl->local_session->get_selectionstart(1), 0),
115 char *text = 0, *data = 0;
116 keyframe->get_contents(&hash, &text, &data);
118 for( int i=0; i<hash.size(); ++i ) {
119 keyframe_data[0].append(new BC_ListBoxItem(hash.get_key(i)));
120 keyframe_data[1].append(new BC_ListBoxItem(hash.get_value(i)));
123 keyframe_data[0].append(new BC_ListBoxItem((char*)"TEXT"));
124 keyframe_data[1].append(new BC_ListBoxItem(text));
127 keyframe_data[0].append(new BC_ListBoxItem((char*)"DATA"));
128 keyframe_data[1].append(new BC_ListBoxItem(data));
134 column_width[0] = mwindow->session->keyframedialog_column1;
135 column_width[1] = mwindow->session->keyframedialog_column2;
136 if( selection >= 0 && selection < keyframe_data[0].size() ) {
137 for( int i=0; i<KEYFRAME_COLUMNS; ++i )
138 keyframe_data[i].get(selection)->set_selected(1);
140 mwindow->gui->unlock_window();
145 void KeyFrameThread::start_window(Plugin *plugin, KeyFrame *keyframe)
148 if( !BC_DialogThread::is_running() ) {
149 if( !mwindow->edl->tracks->plugin_exists(plugin) ) return;
150 this->keyframe = keyframe;
151 this->plugin = plugin;
152 this->preset_text[0] = 0;
153 plugin->calculate_title(plugin_title, 0);
154 sprintf(window_title, _("%s: %s Keyframe"), _(PROGRAM_NAME), plugin_title);
156 // Load all the presets from disk
157 char path[BCTEXTLEN];
159 // system wide presets
160 sprintf(path, "%s/%s", File::get_cindat_path(), FACTORY_FILE);
161 fs.complete_path(path);
162 presets_db->load_from_file(path, 1, 1);
164 sprintf(path, "%s/%s", File::get_config_path(), PRESETS_FILE);
165 fs.complete_path(path);
166 presets_db->load_from_file(path, 0, 0);
168 calculate_preset_list();
173 mwindow->gui->unlock_window();
174 BC_DialogThread::start();
175 mwindow->gui->lock_window("KeyFrameThread::start_window");
178 BC_DialogThread::start();
182 BC_Window* KeyFrameThread::new_gui()
184 mwindow->gui->lock_window("KeyFrameThread::new_gui");
186 int x = mwindow->gui->get_abs_cursor_x(0) -
187 mwindow->session->plugindialog_w / 2;
188 int y = mwindow->gui->get_abs_cursor_y(0) -
189 mwindow->session->plugindialog_h / 2;
191 KeyFrameWindow *window = new KeyFrameWindow(mwindow,
197 window->create_objects();
200 mwindow->gui->unlock_window();
205 void KeyFrameThread::handle_done_event(int result)
209 apply_preset(preset_text, is_factory);
213 void KeyFrameThread::handle_close_event(int result)
219 void KeyFrameThread::close_window()
221 lock_window("KeyFrameThread::close_window");
223 get_gui()->lock_window("KeyFrameThread::close_window");
224 get_gui()->set_done(1);
225 get_gui()->unlock_window();
232 void KeyFrameThread::calculate_preset_list()
234 presets_data->remove_all_objects();
235 is_factories.remove_all();
236 preset_titles.remove_all_objects();
237 int total_presets = presets_db->get_total_presets(plugin_title, 0);
240 presets_db->sort(plugin_title);
242 for( int i=0; i<total_presets; ++i ) {
243 char text[BCTEXTLEN];
244 char *orig_title = presets_db->get_preset_title( plugin_title, i);
245 if( !orig_title ) continue;
246 int is_factory = presets_db->get_is_factory(plugin_title, i);
247 sprintf(text, "%s%s", is_factory ? "*" : "", orig_title);
248 presets_data->append(new BC_ListBoxItem(text));
250 preset_titles.append(strdup(orig_title));
251 is_factories.append(is_factory);
256 void KeyFrameThread::update_gui(int update_value_text)
259 if( BC_DialogThread::is_running() ) {
260 mwindow->gui->lock_window("KeyFrameThread::update_gui");
262 mwindow->gui->unlock_window();
264 lock_window("KeyFrameThread::update_gui");
265 KeyFrameWindow *window = (KeyFrameWindow*)get_gui();
267 window->lock_window("KeyFrameThread::update_gui");
268 window->keyframe_list->update(keyframe_data,
272 window->keyframe_list->get_xposition(),
273 window->keyframe_list->get_yposition(),
274 window->keyframe_list->get_highlighted_item());
275 if( update_value_text &&
276 window->keyframe_list->get_selection_number(0, 0) >= 0 &&
277 window->keyframe_list->get_selection_number(0, 0) < keyframe_data[1].size() ) {
278 window->value_text->update(
279 keyframe_data[1].get(window->keyframe_list->get_selection_number(0, 0))->get_text());
281 window->unlock_window();
288 void KeyFrameThread::save_preset(const char *title, int is_factory)
290 get_gui()->unlock_window();
291 mwindow->gui->lock_window("KeyFrameThread::save_preset");
293 // Test EDL for plugin existence
294 if( !mwindow->edl->tracks->plugin_exists(plugin) ) {
295 mwindow->gui->unlock_window();
296 get_gui()->lock_window("KeyFrameThread::save_preset 2");
300 // Get current plugin keyframe
301 EDL *edl = mwindow->edl;
302 Track *track = plugin->track;
303 KeyFrame *keyframe = plugin->get_prev_keyframe(
304 track->to_units(edl->local_session->get_selectionstart(1), 0),
308 presets_db->save_preset(plugin_title, title, keyframe->get_data());
310 mwindow->gui->unlock_window();
311 get_gui()->lock_window("KeyFrameThread::save_preset 2");
314 calculate_preset_list();
315 ((KeyFrameWindow*)get_gui())->preset_list->update(presets_data,
319 void KeyFrameThread::delete_preset(const char *title, int is_factory)
321 get_gui()->unlock_window();
322 mwindow->gui->lock_window("KeyFrameThread::save_preset");
324 // Test EDL for plugin existence
325 if( !mwindow->edl->tracks->plugin_exists(plugin) ) {
326 mwindow->gui->unlock_window();
327 get_gui()->lock_window("KeyFrameThread::delete_preset 1");
331 presets_db->delete_preset(plugin_title, title, is_factory);
333 mwindow->gui->unlock_window();
334 get_gui()->lock_window("KeyFrameThread::delete_preset 2");
337 calculate_preset_list();
338 ((KeyFrameWindow*)get_gui())->preset_list->update(presets_data,
343 void KeyFrameThread::apply_preset(const char *title, int is_factory)
345 if( presets_db->preset_exists(plugin_title, title, is_factory) ) {
346 get_gui()->unlock_window();
347 mwindow->gui->lock_window("KeyFrameThread::apply_preset");
349 // Test EDL for plugin existence
350 if( !mwindow->edl->tracks->plugin_exists(plugin) ) {
351 mwindow->gui->unlock_window();
352 get_gui()->lock_window("KeyFrameThread::apply_preset 1");
356 mwindow->undo->update_undo_before();
358 #ifdef USE_KEYFRAME_SPANNING
360 presets_db->load_preset(plugin_title, title, &keyframe, is_factory);
361 plugin->keyframes->update_parameter(&keyframe);
363 KeyFrame *keyframe = plugin->get_keyframe();
364 presets_db->load_preset(plugin_title, title, keyframe, is_factory);
366 mwindow->save_backup();
367 mwindow->undo->update_undo_after(_("apply preset"), LOAD_AUTOMATION);
369 mwindow->update_plugin_guis(0);
370 mwindow->gui->draw_overlays(1);
371 mwindow->sync_parameters(CHANGE_PARAMS);
375 mwindow->gui->unlock_window();
376 get_gui()->lock_window("KeyFrameThread::apply_preset");
381 void KeyFrameThread::apply_value()
383 const char *text = 0, *data = 0;
385 KeyFrameWindow *window = (KeyFrameWindow*)get_gui();
386 int selection = window->keyframe_list->get_selection_number(0, 0);
387 //printf("KeyFrameThread::apply_value %d %d\n", __LINE__, selection);
388 if( selection < 0 ) return;
390 if( selection == keyframe_data[0].size() - 2 )
391 text = window->value_text->get_text();
392 else if( selection == keyframe_data[0].size() - 1 )
393 data = window->value_text->get_text();
395 const char *key = keyframe_data[0].get(selection)->get_text();
396 const char *value = window->value_text->get_text();
397 hash = new BC_Hash();
398 hash->update(key, value);
401 get_gui()->unlock_window();
402 mwindow->gui->lock_window("KeyFrameThread::apply_value");
403 if( plugin && mwindow->edl->tracks->plugin_exists(plugin) ) {
404 mwindow->undo->update_undo_before();
405 if( mwindow->session->keyframedialog_all ) {
406 // Search for all keyframes in selection but don't create a new one.
407 Track *track = plugin->track;
408 int64_t start = track->to_units(mwindow->edl->local_session->get_selectionstart(0), 0);
409 int64_t end = track->to_units(mwindow->edl->local_session->get_selectionend(0), 0);
411 KeyFrame *current = (KeyFrame*)plugin->keyframes->last;
412 for( ; current; current=(KeyFrame*)PREVIOUS ) {
414 if( current && current->position < end ) {
415 current->update_parameter(hash, text, data);
416 // Stop at beginning of range
417 if( current->position <= start ) break;
422 current = (KeyFrame*)plugin->keyframes->default_auto;
423 current->update_parameter(hash, text, data);
427 // Create new keyframe if enabled
428 KeyFrame *keyframe = plugin->get_keyframe();
429 keyframe->update_parameter(hash, text, data);
433 printf("KeyFrameThread::apply_value %d: plugin doesn't exist\n", __LINE__);
436 mwindow->save_backup();
437 mwindow->undo->update_undo_after(_("edit keyframe"), LOAD_AUTOMATION);
439 mwindow->update_plugin_guis(0);
440 mwindow->gui->draw_overlays(1);
441 mwindow->sync_parameters(CHANGE_PARAMS);
442 mwindow->gui->unlock_window();
446 get_gui()->lock_window("KeyFrameThread::apply_value");
453 KeyFrameWindow::KeyFrameWindow(MWindow *mwindow,
454 KeyFrameThread *thread,
458 : BC_Window(title_string,
461 mwindow->session->keyframedialog_w,
462 mwindow->session->keyframedialog_h,
469 this->mwindow = mwindow;
470 this->thread = thread;
473 void KeyFrameWindow::create_objects()
475 Theme *theme = mwindow->theme;
477 theme->get_keyframedialog_sizes(this);
478 thread->column_width[0] = mwindow->session->keyframedialog_column1;
479 thread->column_width[1] = mwindow->session->keyframedialog_column2;
480 lock_window("KeyFrameWindow::create_objects");
485 add_subwindow(title1 = new BC_Title(theme->keyframe_list_x,
486 theme->keyframe_list_y - BC_Title::calculate_h(this, (char*)"Py", LARGEFONT) -
487 theme->widget_border, _("Keyframe parameters:"), LARGEFONT));
488 add_subwindow(keyframe_list = new KeyFrameList(thread,
490 theme->keyframe_list_x,
491 theme->keyframe_list_y,
492 theme->keyframe_list_w,
493 theme->keyframe_list_h));
494 // add_subwindow(title2 = new BC_Title(theme->keyframe_text_x,
495 // theme->keyframe_text_y - BC_Title::calculate_h(this, "P") - theme->widget_border,
496 // _("Global Text:")));
497 // add_subwindow(keyframe_text = new KeyFrameText(thread,
499 // theme->keyframe_text_x,
500 // theme->keyframe_text_y,
501 // theme->keyframe_text_w));
502 add_subwindow(title3 = new BC_Title(theme->keyframe_value_x,
503 theme->keyframe_value_y - BC_Title::calculate_h(this, (char*)"P") -
504 theme->widget_border, _("Edit value:")));
505 add_subwindow(value_text = new KeyFrameValue(thread, this,
506 theme->keyframe_value_x, theme->keyframe_value_y, theme->keyframe_value_w));
507 add_subwindow(all_toggle = new KeyFrameAll(thread, this,
508 theme->keyframe_all_x, theme->keyframe_all_y));
511 add_subwindow(title4 = new BC_Title(theme->presets_list_x, theme->presets_list_y -
512 BC_Title::calculate_h(this, (char*)"Py", LARGEFONT) -
513 theme->widget_border, _("Presets:"), LARGEFONT));
514 add_subwindow(preset_list = new KeyFramePresetsList(thread, this,
515 theme->presets_list_x, theme->presets_list_y,
516 theme->presets_list_w, theme->presets_list_h));
517 add_subwindow(title5 = new BC_Title(theme->presets_text_x,
518 theme->presets_text_y - BC_Title::calculate_h(this, (char*)"P") - theme->widget_border,
519 _("Preset title:")));
520 add_subwindow(preset_text = new KeyFramePresetsText(thread, this,
521 theme->presets_text_x, theme->presets_text_y, theme->presets_text_w));
522 add_subwindow(delete_preset = new KeyFramePresetsDelete(thread, this,
523 theme->presets_delete_x, theme->presets_delete_y));
524 add_subwindow(save_preset = new KeyFramePresetsSave(thread, this,
525 theme->presets_save_x, theme->presets_save_y));
526 add_subwindow(apply_preset = new KeyFramePresetsApply(thread, this,
527 theme->presets_apply_x, theme->presets_apply_y));
529 add_subwindow(new KeyFramePresetsOK(thread, this));
530 add_subwindow(new BC_CancelButton(this));
536 // called when going in & out of a factory preset
537 void KeyFrameWindow::update_editing()
539 if( thread->is_factory ) {
540 delete_preset->disable();
541 save_preset->disable();
544 delete_preset->enable();
545 save_preset->enable();
551 int KeyFrameWindow::resize_event(int w, int h)
553 Theme *theme = mwindow->theme;
554 mwindow->session->keyframedialog_w = w;
555 mwindow->session->keyframedialog_h = h;
556 theme->get_keyframedialog_sizes(this);
560 title1->reposition_window(theme->keyframe_list_x,
561 theme->keyframe_list_y - BC_Title::calculate_h(this, (char*)"P") - theme->widget_border);
562 // title2->reposition_window(theme->keyframe_text_x,
563 // theme->keyframe_text_y - BC_Title::calculate_h(this, (char*)"P") - theme->widget_border);
564 title3->reposition_window(theme->keyframe_value_x,
565 theme->keyframe_value_y - BC_Title::calculate_h(this, (char*)"P") - theme->widget_border);
566 keyframe_list->reposition_window(theme->keyframe_list_x,
567 theme->keyframe_list_y,
568 theme->keyframe_list_w,
569 theme->keyframe_list_h);
570 // text->reposition_window(theme->keyframe_text_x,
571 // theme->keyframe_text_y,
572 // theme->keyframe_text_w);
573 value_text->reposition_window(theme->keyframe_value_x,
574 theme->keyframe_value_y,
575 theme->keyframe_value_w);
576 all_toggle->reposition_window(theme->keyframe_all_x,
577 theme->keyframe_all_y);
579 #endif // EDIT_KEYFRAME
584 title4->reposition_window(theme->presets_list_x,
585 theme->presets_list_y - BC_Title::calculate_h(this, (char*)"P") - theme->widget_border);
586 title5->reposition_window(theme->presets_text_x,
587 theme->presets_text_y - BC_Title::calculate_h(this, (char*)"P") - theme->widget_border);
588 preset_list->reposition_window(theme->presets_list_x,
589 theme->presets_list_y,
590 theme->presets_list_w,
591 theme->presets_list_h);
592 preset_text->reposition_window(theme->presets_text_x,
593 theme->presets_text_y,
594 theme->presets_text_w);
595 delete_preset->reposition_window(theme->presets_delete_x,
596 theme->presets_delete_y);
597 save_preset->reposition_window(theme->presets_save_x,
598 theme->presets_save_y);
599 apply_preset->reposition_window(theme->presets_apply_x,
600 theme->presets_apply_y);
611 KeyFrameList::KeyFrameList(KeyFrameThread *thread,
612 KeyFrameWindow *window, int x, int y, int w, int h)
613 : BC_ListBox(x, y, w, h, LISTBOX_TEXT, thread->keyframe_data,
614 thread->column_titles, thread->column_width, KEYFRAME_COLUMNS)
616 this->thread = thread;
617 this->window = window;
618 set_master_column(1, 0);
621 int KeyFrameList::selection_changed()
623 window->value_text->update(
624 thread->keyframe_data[1].get(get_selection_number(0, 0))->get_text());
628 int KeyFrameList::handle_event()
634 int KeyFrameList::column_resize_event()
636 thread->mwindow->session->keyframedialog_column1 = get_column_width(0);
637 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()
666 KeyFrameValue::KeyFrameValue(KeyFrameThread *thread,
667 KeyFrameWindow *window,
677 this->thread = thread;
678 this->window = window;
681 int KeyFrameValue::handle_event()
683 thread->apply_value();
691 KeyFrameAll::KeyFrameAll(KeyFrameThread *thread,
692 KeyFrameWindow *window,
697 thread->mwindow->session->keyframedialog_all,
698 _("Apply to all selected keyframes"))
700 this->thread = thread;
701 this->window = window;
704 int KeyFrameAll::handle_event()
706 thread->mwindow->session->keyframedialog_all = get_value();
710 #endif // EDIT_KEYFRAME
721 KeyFramePresetsList::KeyFramePresetsList(KeyFrameThread *thread,
722 KeyFrameWindow *window,
732 thread->presets_data)
734 this->thread = thread;
735 this->window = window;
738 int KeyFramePresetsList::selection_changed()
740 int number = get_selection_number(0, 0);
742 strcpy(thread->preset_text, thread->preset_titles.get(number));
743 thread->is_factory = thread->is_factories.get(number);
744 // show title without factory symbol in the textbox
745 window->preset_text->update(
746 thread->presets_data->get(number)->get_text());
747 window->update_editing();
753 int KeyFramePresetsList::handle_event()
755 thread->apply_preset(thread->preset_text, thread->is_factory);
761 KeyFramePresetsText::KeyFramePresetsText(KeyFrameThread *thread,
762 KeyFrameWindow *window, int x, int y, int w)
763 : BC_TextBox(x, y, w, 1, thread->preset_text)
765 this->thread = thread;
766 this->window = window;
769 // user entered a title
770 int KeyFramePresetsText::handle_event()
772 strcpy(thread->preset_text, get_text());
773 // once changed, it's now not a factory preset
774 thread->is_factory = 0;
775 window->update_editing();
780 KeyFramePresetsDelete::KeyFramePresetsDelete(KeyFrameThread *thread,
781 KeyFrameWindow *window,
784 : BC_GenericButton(x, y, _("Delete"))
786 this->thread = thread;
787 this->window = window;
790 int KeyFramePresetsDelete::handle_event()
792 if( !thread->is_factory ) {
793 thread->delete_preset(thread->preset_text, thread->is_factory);
799 KeyFramePresetsSave::KeyFramePresetsSave(KeyFrameThread *thread,
800 KeyFrameWindow *window,
803 : BC_GenericButton(x, y, C_("Save"))
805 this->thread = thread;
806 this->window = window;
809 int KeyFramePresetsSave::handle_event()
811 if( !thread->is_factory ) {
812 thread->save_preset(thread->preset_text, thread->is_factory);
824 KeyFramePresetsApply::KeyFramePresetsApply(KeyFrameThread *thread,
825 KeyFrameWindow *window,
828 : BC_GenericButton(x, y, _("Apply"))
830 this->thread = thread;
831 this->window = window;
834 int KeyFramePresetsApply::handle_event()
836 thread->apply_preset(thread->preset_text, thread->is_factory);
841 KeyFramePresetsOK::KeyFramePresetsOK(KeyFrameThread *thread,
842 KeyFrameWindow *window)
843 : BC_OKButton(window)
845 this->thread = thread;
846 this->window = window;
849 int KeyFramePresetsOK::keypress_event()
851 if( get_keypress() == RETURN ) {
853 if( thread->presets_db->preset_exists(thread->plugin_title,
854 thread->preset_text, thread->is_factory) ) {
859 if( !thread->is_factory ) {
860 thread->save_preset(thread->preset_text, thread->is_factory);