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 if( !plugin || !mwindow->edl->tracks->plugin_exists(plugin) ) {
96 mwindow->gui->unlock_window();
100 KeyFrame *keyframe = 0;
101 if( this->keyframe && plugin->keyframe_exists(this->keyframe) ) {
102 // If user edited a specific keyframe, use it.
103 keyframe = this->keyframe;
106 if( plugin->track ) {
107 // Use currently highlighted keyframe
108 keyframe = plugin->get_prev_keyframe(
109 plugin->track->to_units(
110 mwindow->edl->local_session->get_selectionstart(1), 0),
116 char *text = 0, *data = 0;
117 keyframe->get_contents(&hash, &text, &data);
119 for( int i=0; i<hash.size(); ++i ) {
120 keyframe_data[0].append(new BC_ListBoxItem(hash.get_key(i)));
121 keyframe_data[1].append(new BC_ListBoxItem(hash.get_value(i)));
124 keyframe_data[0].append(new BC_ListBoxItem((char*)"TEXT"));
125 keyframe_data[1].append(new BC_ListBoxItem(text));
128 keyframe_data[0].append(new BC_ListBoxItem((char*)"DATA"));
129 keyframe_data[1].append(new BC_ListBoxItem(data));
135 column_width[0] = mwindow->session->keyframedialog_column1;
136 column_width[1] = mwindow->session->keyframedialog_column2;
137 if( selection >= 0 && selection < keyframe_data[0].size() ) {
138 for( int i=0; i<KEYFRAME_COLUMNS; ++i )
139 keyframe_data[i].get(selection)->set_selected(1);
141 mwindow->gui->unlock_window();
146 void KeyFrameThread::start_window(Plugin *plugin, KeyFrame *keyframe)
149 if( !BC_DialogThread::is_running() ) {
150 if( !mwindow->edl->tracks->plugin_exists(plugin) ) return;
151 this->keyframe = keyframe;
152 this->plugin = plugin;
153 this->preset_text[0] = 0;
154 plugin->calculate_title(plugin_title, 0);
155 sprintf(window_title, _("%s: %s Keyframe"), _(PROGRAM_NAME), plugin_title);
157 // Load all the presets from disk
158 char path[BCTEXTLEN];
160 // system wide presets
161 sprintf(path, "%s/%s", File::get_cindat_path(), FACTORY_FILE);
162 fs.complete_path(path);
163 presets_db->load_from_file(path, 1, 1);
165 sprintf(path, "%s/%s", File::get_config_path(), PRESETS_FILE);
166 fs.complete_path(path);
167 presets_db->load_from_file(path, 0, 0);
169 calculate_preset_list();
174 mwindow->gui->unlock_window();
175 BC_DialogThread::start();
176 mwindow->gui->lock_window("KeyFrameThread::start_window");
179 BC_DialogThread::start();
183 BC_Window* KeyFrameThread::new_gui()
185 mwindow->gui->lock_window("KeyFrameThread::new_gui");
187 int x = mwindow->gui->get_abs_cursor_x(0) -
188 mwindow->session->plugindialog_w / 2;
189 int y = mwindow->gui->get_abs_cursor_y(0) -
190 mwindow->session->plugindialog_h / 2;
192 KeyFrameWindow *window = new KeyFrameWindow(mwindow,
198 window->create_objects();
201 mwindow->gui->unlock_window();
206 void KeyFrameThread::handle_done_event(int result)
210 apply_preset(preset_text, is_factory);
214 void KeyFrameThread::handle_close_event(int result)
220 void KeyFrameThread::close_window()
222 lock_dialog("KeyFrameThread::close_window");
224 get_gui()->lock_window("KeyFrameThread::close_window");
225 get_gui()->set_done(1);
226 get_gui()->unlock_window();
233 void KeyFrameThread::calculate_preset_list()
235 presets_data->remove_all_objects();
236 is_factories.remove_all();
237 preset_titles.remove_all_objects();
238 int total_presets = presets_db->get_total_presets(plugin_title, 0);
241 presets_db->sort(plugin_title);
243 for( int i=0; i<total_presets; ++i ) {
244 char text[BCTEXTLEN];
245 char *orig_title = presets_db->get_preset_title( plugin_title, i);
246 if( !orig_title ) continue;
247 int is_factory = presets_db->get_is_factory(plugin_title, i);
248 sprintf(text, "%s%s", is_factory ? "*" : "", orig_title);
249 presets_data->append(new BC_ListBoxItem(text));
251 preset_titles.append(strdup(orig_title));
252 is_factories.append(is_factory);
257 void KeyFrameThread::update_gui(int update_value_text)
260 if( BC_DialogThread::is_running() ) {
261 mwindow->gui->lock_window("KeyFrameThread::update_gui");
263 mwindow->gui->unlock_window();
265 lock_dialog("KeyFrameThread::update_gui");
266 KeyFrameWindow *window = (KeyFrameWindow*)get_gui();
268 window->lock_window("KeyFrameThread::update_gui");
269 window->keyframe_list->update(keyframe_data,
273 window->keyframe_list->get_xposition(),
274 window->keyframe_list->get_yposition(),
275 window->keyframe_list->get_highlighted_item());
276 if( update_value_text &&
277 window->keyframe_list->get_selection_number(0, 0) >= 0 &&
278 window->keyframe_list->get_selection_number(0, 0) < keyframe_data[1].size() ) {
279 window->value_text->update(
280 keyframe_data[1].get(window->keyframe_list->get_selection_number(0, 0))->get_text());
282 window->unlock_window();
289 void KeyFrameThread::save_preset(const char *title, int is_factory)
291 get_gui()->unlock_window();
292 mwindow->gui->lock_window("KeyFrameThread::save_preset");
294 // Test EDL for plugin existence
295 if( !mwindow->edl->tracks->plugin_exists(plugin) ) {
296 mwindow->gui->unlock_window();
297 get_gui()->lock_window("KeyFrameThread::save_preset 2");
301 // Get current plugin keyframe
302 EDL *edl = mwindow->edl;
303 Track *track = plugin->track;
304 KeyFrame *keyframe = plugin->get_prev_keyframe(
305 track->to_units(edl->local_session->get_selectionstart(1), 0),
309 presets_db->save_preset(plugin_title, title, keyframe->get_data());
311 mwindow->gui->unlock_window();
312 get_gui()->lock_window("KeyFrameThread::save_preset 2");
315 calculate_preset_list();
316 ((KeyFrameWindow*)get_gui())->preset_list->update(presets_data,
320 void KeyFrameThread::delete_preset(const char *title, int is_factory)
322 get_gui()->unlock_window();
323 mwindow->gui->lock_window("KeyFrameThread::save_preset");
325 // Test EDL for plugin existence
326 if( !mwindow->edl->tracks->plugin_exists(plugin) ) {
327 mwindow->gui->unlock_window();
328 get_gui()->lock_window("KeyFrameThread::delete_preset 1");
332 presets_db->delete_preset(plugin_title, title, is_factory);
334 mwindow->gui->unlock_window();
335 get_gui()->lock_window("KeyFrameThread::delete_preset 2");
338 calculate_preset_list();
339 ((KeyFrameWindow*)get_gui())->preset_list->update(presets_data,
344 void KeyFrameThread::apply_preset(const char *title, int is_factory)
346 if( presets_db->preset_exists(plugin_title, title, is_factory) ) {
347 get_gui()->unlock_window();
348 mwindow->gui->lock_window("KeyFrameThread::apply_preset");
350 // Test EDL for plugin existence
351 if( !mwindow->edl->tracks->plugin_exists(plugin) ) {
352 mwindow->gui->unlock_window();
353 get_gui()->lock_window("KeyFrameThread::apply_preset 1");
357 mwindow->undo->update_undo_before();
359 #ifdef USE_KEYFRAME_SPANNING
361 presets_db->load_preset(plugin_title, title, &keyframe, is_factory);
362 plugin->keyframes->update_parameter(&keyframe);
364 KeyFrame *keyframe = plugin->get_keyframe();
365 presets_db->load_preset(plugin_title, title, keyframe, is_factory);
367 mwindow->save_backup();
368 mwindow->undo->update_undo_after(_("apply preset"), LOAD_AUTOMATION);
370 mwindow->update_plugin_guis(0);
371 mwindow->gui->draw_overlays(1);
372 mwindow->sync_parameters(CHANGE_PARAMS);
376 mwindow->gui->unlock_window();
377 get_gui()->lock_window("KeyFrameThread::apply_preset");
383 void KeyFrameThread::apply_value()
385 const char *text = 0, *data = 0;
387 KeyFrameWindow *window = (KeyFrameWindow*)get_gui();
388 int selection = window->keyframe_list->get_selection_number(0, 0);
389 //printf("KeyFrameThread::apply_value %d %d\n", __LINE__, selection);
390 if( selection < 0 ) return;
392 if( selection == keyframe_data[0].size() - 2 )
393 text = window->value_text->get_text();
394 else if( selection == keyframe_data[0].size() - 1 )
395 data = window->value_text->get_text();
397 const char *key = keyframe_data[0].get(selection)->get_text();
398 const char *value = window->value_text->get_text();
399 hash = new BC_Hash();
400 hash->update(key, value);
403 get_gui()->unlock_window();
404 mwindow->gui->lock_window("KeyFrameThread::apply_value");
405 if( plugin && mwindow->edl->tracks->plugin_exists(plugin) ) {
406 mwindow->undo->update_undo_before();
407 if( mwindow->session->keyframedialog_all ) {
408 // Search for all keyframes in selection but don't create a new one.
409 Track *track = plugin->track;
410 int64_t start = track->to_units(mwindow->edl->local_session->get_selectionstart(0), 0);
411 int64_t end = track->to_units(mwindow->edl->local_session->get_selectionend(0), 0);
413 KeyFrame *current = (KeyFrame*)plugin->keyframes->last;
414 for( ; current; current=(KeyFrame*)PREVIOUS ) {
416 if( current && current->position < end ) {
417 current->update_parameter(hash, text, data);
418 // Stop at beginning of range
419 if( current->position <= start ) break;
424 current = (KeyFrame*)plugin->keyframes->default_auto;
425 current->update_parameter(hash, text, data);
429 // Create new keyframe if enabled
430 KeyFrame *keyframe = plugin->get_keyframe();
431 keyframe->update_parameter(hash, text, data);
435 printf("KeyFrameThread::apply_value %d: plugin doesn't exist\n", __LINE__);
438 mwindow->save_backup();
439 mwindow->undo->update_undo_after(_("edit keyframe"), LOAD_AUTOMATION);
441 mwindow->update_plugin_guis(0);
442 mwindow->gui->draw_overlays(1);
443 mwindow->sync_parameters(CHANGE_PARAMS);
444 mwindow->gui->unlock_window();
448 get_gui()->lock_window("KeyFrameThread::apply_value");
455 KeyFrameWindow::KeyFrameWindow(MWindow *mwindow, KeyFrameThread *thread,
456 int x, int y, char *title_string)
457 : BC_Window(title_string, x, y,
458 mwindow->session->keyframedialog_w,
459 mwindow->session->keyframedialog_h,
460 xS(320), yS(240), 1, 0, 1)
462 this->mwindow = mwindow;
463 this->thread = thread;
466 void KeyFrameWindow::create_objects()
468 Theme *theme = mwindow->theme;
470 theme->get_keyframedialog_sizes(this);
471 thread->column_width[0] = mwindow->session->keyframedialog_column1;
472 thread->column_width[1] = mwindow->session->keyframedialog_column2;
473 lock_window("KeyFrameWindow::create_objects");
477 int ky = theme->keyframe_list_y - theme->widget_border -
478 BC_Title::calculate_h(this, (char*)"Py", LARGEFONT);
479 add_subwindow(title1 = new BC_Title(theme->keyframe_list_x, ky,
480 _("Keyframe parameters:"), LARGEFONT));
481 add_subwindow(keyframe_list = new KeyFrameList(thread, this,
482 theme->keyframe_list_x, theme->keyframe_list_y,
483 theme->keyframe_list_w, theme->keyframe_list_h));
484 // add_subwindow(title2 = new BC_Title(theme->keyframe_text_x,
485 // theme->keyframe_text_y - theme->widget_border -
486 // BC_Title::calculate_h(this, "P"), _("Global Text:")));
487 // add_subwindow(keyframe_text = new KeyFrameText(thread, this,
488 // theme->keyframe_text_x, theme->keyframe_text_y,
489 // theme->keyframe_text_w));
490 int ey = theme->keyframe_value_y - theme->widget_border -
491 BC_Title::calculate_h(this, "P");
492 add_subwindow(title3 = new BC_Title(theme->keyframe_value_x, ey,
494 add_subwindow(value_text = new KeyFrameValue(thread, this,
495 theme->keyframe_value_x, theme->keyframe_value_y, theme->keyframe_value_w));
496 add_subwindow(all_toggle = new KeyFrameAll(thread, this,
497 theme->keyframe_all_x, theme->keyframe_all_y));
500 int ty = theme->presets_list_y - theme->widget_border -
501 BC_Title::calculate_h(this, (char*)"Py", LARGEFONT);
502 add_subwindow(title4 = new BC_Title(theme->presets_list_x, ty,
503 _("Presets:"), LARGEFONT));
504 add_subwindow(preset_list = new KeyFramePresetsList(thread, this,
505 theme->presets_list_x, theme->presets_list_y,
506 theme->presets_list_w, theme->presets_list_h));
507 int py = theme->presets_text_y - theme->widget_border -
508 BC_Title::calculate_h(this, "Py");
509 add_subwindow(title5 = new BC_Title(theme->presets_text_x, py,
510 _("Preset title:")));
511 add_subwindow(preset_text = new KeyFramePresetsText(thread, this,
512 theme->presets_text_x, theme->presets_text_y, theme->presets_text_w));
513 add_subwindow(delete_preset = new KeyFramePresetsDelete(thread, this,
514 theme->presets_delete_x, theme->presets_delete_y));
515 add_subwindow(save_preset = new KeyFramePresetsSave(thread, this,
516 theme->presets_save_x, theme->presets_save_y));
517 add_subwindow(apply_preset = new KeyFramePresetsApply(thread, this,
518 theme->presets_apply_x, theme->presets_apply_y));
520 add_subwindow(new KeyFramePresetsOK(thread, this));
521 add_subwindow(new BC_CancelButton(this));
527 // called when going in & out of a factory preset
528 void KeyFrameWindow::update_editing()
530 if( thread->is_factory ) {
531 delete_preset->disable();
532 save_preset->disable();
535 delete_preset->enable();
536 save_preset->enable();
540 int KeyFrameWindow::resize_event(int w, int h)
542 Theme *theme = mwindow->theme;
543 mwindow->session->keyframedialog_w = w;
544 mwindow->session->keyframedialog_h = h;
545 theme->get_keyframedialog_sizes(this);
548 int ky = theme->keyframe_list_y - theme->widget_border -
549 BC_Title::calculate_h(this, (char*)"Py", LARGEFONT);
550 title1->reposition_window(theme->keyframe_list_x, ky);
551 // title2->reposition_window(theme->keyframe_text_x,
552 // theme->keyframe_text_y - theme->widget_border -;
553 // BC_Title::calculate_h(this, (char*)"P"));
554 int ey = theme->keyframe_value_y - theme->widget_border -
555 BC_Title::calculate_h(this, "P");
556 title3->reposition_window(theme->keyframe_value_x, ey);
557 keyframe_list->reposition_window(theme->keyframe_list_x, theme->keyframe_list_y,
558 theme->keyframe_list_w, theme->keyframe_list_h);
559 // text->reposition_window(theme->keyframe_text_x, theme->keyframe_text_y,
560 // theme->keyframe_text_w);
561 value_text->reposition_window(theme->keyframe_value_x,
562 theme->keyframe_value_y,
563 theme->keyframe_value_w);
564 all_toggle->reposition_window(theme->keyframe_all_x,
565 theme->keyframe_all_y);
567 int ty = theme->presets_list_y - theme->widget_border -
568 BC_Title::calculate_h(this, (char*)"Py", LARGEFONT);
569 title4->reposition_window(theme->presets_list_x, ty);
570 int py = theme->presets_text_y - theme->widget_border -
571 BC_Title::calculate_h(this, "Py");
572 title5->reposition_window(theme->presets_text_x, py);
575 preset_list->reposition_window(theme->presets_list_x,
576 theme->presets_list_y,
577 theme->presets_list_w,
578 theme->presets_list_h);
579 preset_text->reposition_window(theme->presets_text_x,
580 theme->presets_text_y,
581 theme->presets_text_w);
582 delete_preset->reposition_window(theme->presets_delete_x,
583 theme->presets_delete_y);
584 save_preset->reposition_window(theme->presets_save_x,
585 theme->presets_save_y);
586 apply_preset->reposition_window(theme->presets_apply_x,
587 theme->presets_apply_y);
597 KeyFrameList::KeyFrameList(KeyFrameThread *thread,
598 KeyFrameWindow *window, int x, int y, int w, int h)
599 : BC_ListBox(x, y, w, h, LISTBOX_TEXT, thread->keyframe_data,
600 thread->column_titles, thread->column_width, KEYFRAME_COLUMNS)
602 this->thread = thread;
603 this->window = window;
604 set_master_column(1, 0);
607 int KeyFrameList::selection_changed()
609 window->value_text->update(
610 thread->keyframe_data[1].get(get_selection_number(0, 0))->get_text());
614 int KeyFrameList::handle_event()
620 int KeyFrameList::column_resize_event()
622 thread->mwindow->session->keyframedialog_column1 = get_column_width(0);
623 thread->mwindow->session->keyframedialog_column2 = get_column_width(1);
628 // KeyFrameText::KeyFrameText(KeyFrameThread *thread,
629 // KeyFrameWindow *window,
639 // this->thread = thread;
640 // this->window = window;
643 // int KeyFrameText::handle_event()
648 KeyFrameValue::KeyFrameValue(KeyFrameThread *thread,
649 KeyFrameWindow *window,
659 this->thread = thread;
660 this->window = window;
663 int KeyFrameValue::handle_event()
665 thread->apply_value();
669 KeyFrameAll::KeyFrameAll(KeyFrameThread *thread,
670 KeyFrameWindow *window, int x, int y)
672 thread->mwindow->session->keyframedialog_all,
673 _("Apply to all selected keyframes"))
675 this->thread = thread;
676 this->window = window;
679 int KeyFrameAll::handle_event()
681 thread->mwindow->session->keyframedialog_all = get_value();
685 #endif // EDIT_KEYFRAME
688 KeyFramePresetsList::KeyFramePresetsList(KeyFrameThread *thread,
689 KeyFrameWindow *window, int x, int y, int w, int h)
690 : BC_ListBox(x, y, w, h, LISTBOX_TEXT, thread->presets_data)
692 this->thread = thread;
693 this->window = window;
696 int KeyFramePresetsList::selection_changed()
698 int number = get_selection_number(0, 0);
700 strcpy(thread->preset_text, thread->preset_titles.get(number));
701 thread->is_factory = thread->is_factories.get(number);
702 // show title without factory symbol in the textbox
703 window->preset_text->update(
704 thread->presets_data->get(number)->get_text());
705 window->update_editing();
711 int KeyFramePresetsList::handle_event()
713 thread->apply_preset(thread->preset_text, thread->is_factory);
719 KeyFramePresetsText::KeyFramePresetsText(KeyFrameThread *thread,
720 KeyFrameWindow *window, int x, int y, int w)
721 : BC_TextBox(x, y, w, 1, thread->preset_text)
723 this->thread = thread;
724 this->window = window;
727 // user entered a title
728 int KeyFramePresetsText::handle_event()
730 strcpy(thread->preset_text, get_text());
731 // once changed, it's now not a factory preset
732 thread->is_factory = 0;
733 window->update_editing();
738 KeyFramePresetsDelete::KeyFramePresetsDelete(KeyFrameThread *thread,
739 KeyFrameWindow *window,
742 : BC_GenericButton(x, y, _("Delete"))
744 this->thread = thread;
745 this->window = window;
748 int KeyFramePresetsDelete::handle_event()
750 if( !thread->is_factory ) {
751 thread->delete_preset(thread->preset_text, thread->is_factory);
757 KeyFramePresetsSave::KeyFramePresetsSave(KeyFrameThread *thread,
758 KeyFrameWindow *window,
761 : BC_GenericButton(x, y, C_("Save"))
763 this->thread = thread;
764 this->window = window;
767 int KeyFramePresetsSave::handle_event()
769 if( !thread->is_factory ) {
770 thread->save_preset(thread->preset_text, thread->is_factory);
776 KeyFramePresetsApply::KeyFramePresetsApply(KeyFrameThread *thread,
777 KeyFrameWindow *window,
780 : BC_GenericButton(x, y, _("Apply"))
782 this->thread = thread;
783 this->window = window;
786 int KeyFramePresetsApply::handle_event()
788 thread->apply_preset(thread->preset_text, thread->is_factory);
793 KeyFramePresetsOK::KeyFramePresetsOK(KeyFrameThread *thread,
794 KeyFrameWindow *window)
795 : BC_OKButton(window)
797 this->thread = thread;
798 this->window = window;
801 int KeyFramePresetsOK::keypress_event()
803 if( get_keypress() == RETURN ) {
805 if( thread->presets_db->preset_exists(thread->plugin_title,
806 thread->preset_text, thread->is_factory) ) {
811 if( !thread->is_factory ) {
812 thread->save_preset(thread->preset_text, thread->is_factory);