Merge CV, ver=5.1; ops/methods from HV, and interface from CV where possible
[goodguy/history.git] / cinelerra-5.1 / cinelerra / keyframegui.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 "bchash.h"
23 #include "bcsignals.h"
24 #include "edl.h"
25 #include "keyframe.h"
26 #include "keyframes.h"
27 #include "keyframegui.h"
28 #include "keys.h"
29 #include "language.h"
30 #include "localsession.h"
31 #include "mainsession.h"
32 #include "mainundo.h"
33 #include "mwindow.h"
34 #include "mwindowgui.h"
35 #include "plugin.h"
36 #include "theme.h"
37 #include "trackcanvas.h"
38 #include "tracks.h"
39
40
41 KeyFrameThread::KeyFrameThread(MWindow *mwindow)
42  : BC_DialogThread()
43 {
44         this->mwindow = mwindow;
45         plugin = 0;
46         keyframe = 0;
47         keyframe_data = new ArrayList<BC_ListBoxItem*>[KEYFRAME_COLUMNS];
48         plugin_title[0] = 0;
49         window_title[0] = 0;
50         column_titles[0] = (char*)_("Parameter");
51         column_titles[1] = (char*)_("Value");
52         column_width[0] = 0;
53         column_width[1] = 0;
54 }
55
56 KeyFrameThread::~KeyFrameThread()
57 {
58         close_window();
59         for(int i = 0; i < KEYFRAME_COLUMNS; i++)
60                 keyframe_data[i].remove_all_objects();
61         delete [] keyframe_data;
62 }
63
64
65 void KeyFrameThread::update_values()
66 {
67 // Get the current selection before deleting the tables
68         int selection = -1;
69         for(int i = 0; i < keyframe_data[0].size(); i++) {
70                 if(keyframe_data[0].get(i)->get_selected()) {
71                         selection = i;
72                         break;
73                 }
74         }
75
76         for(int i = 0; i < KEYFRAME_COLUMNS; i++)
77                 keyframe_data[i].remove_all_objects();
78
79
80 // Must lock main window to read keyframe
81         mwindow->gui->lock_window("KeyFrameThread::update_values");
82         if(!plugin || !mwindow->edl->tracks->plugin_exists(plugin)) {
83                 mwindow->gui->unlock_window();
84                 return;
85         }
86
87         KeyFrame *keyframe = 0;
88         if(this->keyframe && plugin->keyframe_exists(this->keyframe)) {
89 // If user edited a specific keyframe, use it.
90                 keyframe = this->keyframe;
91         }
92         else if(plugin->track) {
93 // Use currently highlighted keyframe
94                 keyframe = plugin->get_prev_keyframe(
95                         plugin->track->to_units(
96                                 mwindow->edl->local_session->get_selectionstart(1), 0),
97                         PLAY_FORWARD);
98         }
99
100         if(keyframe) {
101                 BC_Hash hash;
102                 char *text = 0, *extra = 0;
103                 keyframe->get_contents(&hash, &text, &extra);
104                 
105                 for(int i = 0; i < hash.size(); i++)
106                 {
107                         keyframe_data[0].append(new BC_ListBoxItem(hash.get_key(i)));
108                         keyframe_data[1].append(new BC_ListBoxItem(hash.get_value(i)));
109                 }
110                 keyframe_data[0].append(new BC_ListBoxItem((char*)_("TEXT")));
111                 keyframe_data[1].append(new BC_ListBoxItem(text));
112                 
113                 delete [] text;
114                 delete [] extra;
115         }
116
117         column_width[0] = mwindow->session->keyframedialog_column1;
118         column_width[1] = mwindow->session->keyframedialog_column2;
119         if(selection >= 0 && selection < keyframe_data[0].size()) {
120                 for(int i = 0; i < KEYFRAME_COLUMNS; i++)
121                         keyframe_data[i].get(selection)->set_selected(1);
122         }
123         mwindow->gui->unlock_window();
124 }
125
126
127 void KeyFrameThread::start_window(Plugin *plugin, KeyFrame *keyframe)
128 {
129
130         if(!BC_DialogThread::is_running()) {
131                 if(!mwindow->edl->tracks->plugin_exists(plugin)) return;
132                 this->keyframe = keyframe;
133                 this->plugin = plugin;
134                 plugin->calculate_title(plugin_title, 0);
135                 sprintf(window_title, _(PROGRAM_NAME ": %s Keyframe"), plugin_title);
136                 update_values();
137                 mwindow->gui->unlock_window();
138                 BC_DialogThread::start();
139                 mwindow->gui->lock_window("KeyFrameThread::start_window");
140         }
141         else {
142                 BC_DialogThread::start();
143         }
144 }
145
146 BC_Window* KeyFrameThread::new_gui()
147 {
148         mwindow->gui->lock_window("KeyFrameThread::new_gui");
149         
150         int x = mwindow->gui->get_abs_cursor_x(0) - 
151                 mwindow->session->plugindialog_w / 2;
152         int y = mwindow->gui->get_abs_cursor_y(0) - 
153                 mwindow->session->plugindialog_h / 2;
154
155         KeyFrameWindow *window = new KeyFrameWindow(mwindow, 
156                 this, x, y, window_title);
157         window->create_objects();
158
159         mwindow->gui->unlock_window();
160         return window;
161 }
162
163 void KeyFrameThread::handle_done_event(int result)
164 {
165         if( !result )
166                 apply_value();
167 }
168
169 void KeyFrameThread::handle_close_event(int result)
170 {
171         plugin = 0;
172         keyframe = 0;
173 }
174
175
176 void KeyFrameThread::update_gui(int update_value_text)
177 {
178         if(BC_DialogThread::is_running()) {
179                 mwindow->gui->lock_window("KeyFrameThread::update_gui");
180                 update_values();
181                 mwindow->gui->unlock_window();
182
183                 lock_window("KeyFrameThread::update_gui");
184                 KeyFrameWindow *window = (KeyFrameWindow*)get_gui();
185                 if(window) {
186                         window->lock_window("KeyFrameThread::update_gui");
187                         window->keyframe_list->update(keyframe_data,
188                                 (const char **)column_titles,
189                                 column_width,
190                                 KEYFRAME_COLUMNS,
191                                 window->keyframe_list->get_xposition(),
192                                 window->keyframe_list->get_yposition(),
193                                 window->keyframe_list->get_highlighted_item());
194                         if( update_value_text ) {
195                                 int selection_number = window->keyframe_list->get_selection_number(0, 0);
196                                 if( selection_number >= 0 && selection_number < keyframe_data[1].size()) {
197                                         char *edit_value = keyframe_data[1].get(selection_number)->get_text();
198                                         window->value_text->update(edit_value);
199                                 }
200                         }
201                         window->unlock_window();
202                 }
203                 unlock_window();
204         }
205 }
206
207 void KeyFrameThread::apply_value()
208 {
209         const char *text = 0;
210         BC_Hash hash;
211         KeyFrameWindow *window = (KeyFrameWindow*)get_gui();
212         int selection = window->keyframe_list->get_selection_number(0, 0);
213 //printf("KeyFrameThread::apply_value %d %d\n", __LINE__, selection);
214         if(selection < 0) return;
215         
216         if(selection == keyframe_data[0].size() - 1)
217                 text = window->value_text->get_text();
218         else {
219                 char *key = keyframe_data[0].get(selection)->get_text();
220                 const char *value = window->value_text->get_text();
221                 hash.update(key, value);
222         }
223
224         get_gui()->unlock_window();
225         mwindow->gui->lock_window("KeyFrameThread::apply_value");
226         if(plugin && mwindow->edl->tracks->plugin_exists(plugin)) {
227                 mwindow->undo->update_undo_before();
228                 if(mwindow->session->keyframedialog_all) {
229 // Search for all keyframes in selection but don't create a new one.
230                         Track *track = plugin->track;
231                         int64_t start = track->to_units(mwindow->edl->local_session->get_selectionstart(0), 0);
232                         int64_t end = track->to_units(mwindow->edl->local_session->get_selectionend(0), 0);
233                         int got_it = 0;
234                         for(KeyFrame *current = (KeyFrame*)plugin->keyframes->last;
235                                 current;
236                                 current = (KeyFrame*)PREVIOUS) {
237                                 got_it = 1;
238                                 if(current && current->position < end) {
239                                         current->update_parameter(&hash, text, 0);
240 // Stop at beginning of range
241                                         if(current->position <= start) break;
242                                 }
243                         }
244
245                         if(!got_it) {
246                                 KeyFrame* keyframe = (KeyFrame*)plugin->keyframes->default_auto;
247                                 keyframe->update_parameter(&hash, text, 0);
248                         }
249                 }
250                 else {
251 // Create new keyframe if enabled
252                         KeyFrame *keyframe = plugin->get_keyframe();
253                         keyframe->update_parameter(&hash, text, 0);
254                 }
255         }
256         else {
257 printf("KeyFrameThread::apply_value %d: plugin doesn't exist\n", __LINE__);
258         }
259
260         mwindow->save_backup();
261         mwindow->undo->update_undo_after(_("edit keyframe"), LOAD_AUTOMATION); 
262
263         mwindow->update_plugin_guis(0);
264         mwindow->gui->draw_overlays(1);
265         mwindow->sync_parameters(CHANGE_PARAMS);
266
267
268
269         mwindow->gui->unlock_window();
270
271         update_gui(0);
272
273         get_gui()->lock_window("KeyFrameThread::apply_value");
274 }
275
276
277 KeyFrameWindow::KeyFrameWindow(MWindow *mwindow,
278         KeyFrameThread *thread, int x, int y, char *title_string)
279  : BC_Window(title_string, x, y,
280         mwindow->session->keyframedialog_w, 
281         mwindow->session->keyframedialog_h, 
282         320, 240, 1, 0, 1)
283 {
284         this->mwindow = mwindow;
285         this->thread = thread;
286 }
287
288 void KeyFrameWindow::create_objects()
289 {
290         Theme *theme = mwindow->theme;
291
292         theme->get_keyframedialog_sizes(this);
293         thread->column_width[0] = mwindow->session->keyframedialog_column1;
294         thread->column_width[1] = mwindow->session->keyframedialog_column2;
295         lock_window("KeyFrameWindow::create_objects");
296
297         add_subwindow(title1 = new BC_Title(theme->keyframe_list_x,
298                 theme->keyframe_list_y - 
299                         BC_Title::calculate_h(this, (char*)"Py", LARGEFONT) - 
300                         theme->widget_border,
301                 _("Keyframe parameters:"), LARGEFONT));
302         add_subwindow(keyframe_list = new KeyFrameList(thread,
303                 this, theme->keyframe_list_x, theme->keyframe_list_y,
304                 theme->keyframe_list_w, theme->keyframe_list_h));
305         add_subwindow(title3 = new BC_Title(theme->keyframe_value_x,
306                 theme->keyframe_value_y - BC_Title::calculate_h(this, (char*)"P") - theme->widget_border,
307                 _("Edit value:")));
308         add_subwindow(value_text = new KeyFrameValue(thread,
309                 this, theme->keyframe_value_x, theme->keyframe_value_y, theme->keyframe_value_w));
310         add_subwindow(all_toggle = new KeyFrameAll(thread,
311                 this, theme->keyframe_all_x, theme->keyframe_all_y));
312
313         add_subwindow(new KeyFrameParamsOK(thread, this));
314         add_subwindow(new BC_CancelButton(this));
315
316         show_window();
317         unlock_window();
318 }
319
320 int KeyFrameWindow::resize_event(int w, int h)
321 {
322         Theme *theme = mwindow->theme;
323         mwindow->session->keyframedialog_w = w;
324         mwindow->session->keyframedialog_h = h;
325         theme->get_keyframedialog_sizes(this);
326
327         title1->reposition_window(theme->keyframe_list_x,
328                 theme->keyframe_list_y - BC_Title::calculate_h(this, (char*)"P") - theme->widget_border);
329         title3->reposition_window(theme->keyframe_value_x,
330                 theme->keyframe_value_y - BC_Title::calculate_h(this, (char*)"P") - theme->widget_border);
331         keyframe_list->reposition_window(theme->keyframe_list_x, theme->keyframe_list_y,
332                 theme->keyframe_list_w, theme->keyframe_list_h);
333         value_text->reposition_window(theme->keyframe_value_x, theme->keyframe_value_y,
334                 theme->keyframe_value_w);
335         all_toggle->reposition_window(theme->keyframe_all_x, theme->keyframe_all_y);
336
337         return 0;
338 }
339
340 KeyFrameList::KeyFrameList(KeyFrameThread *thread,
341         KeyFrameWindow *window, int x, int y, int w, int h)
342  : BC_ListBox(x, y, w, h, LISTBOX_TEXT,
343         thread->keyframe_data, (const char **)thread->column_titles,
344         thread->column_width, KEYFRAME_COLUMNS)
345 {
346         this->thread = thread;
347         this->window = window;
348 }
349
350 int KeyFrameList::selection_changed()
351 {
352         window->value_text->update(
353                 thread->keyframe_data[1].get(get_selection_number(0, 0))->get_text());
354         return 0;
355 }
356
357 int KeyFrameList::handle_event()
358 {
359         window->set_done(0);
360         return 0;
361 }
362
363 int KeyFrameList::column_resize_event()
364 {
365         thread->mwindow->session->keyframedialog_column1 = get_column_width(0);
366         thread->mwindow->session->keyframedialog_column2 = get_column_width(1);
367         return 1;
368 }
369
370
371 KeyFrameValue::KeyFrameValue(KeyFrameThread *thread,
372         KeyFrameWindow *window, int x, int y, int w)
373  : BC_TextBox(x, y, w, 1, "")
374 {
375         this->thread = thread;
376         this->window = window;
377 }
378
379 int KeyFrameValue::handle_event()
380 {
381         thread->update_values();
382         return 0;
383 }
384
385
386 KeyFrameAll::KeyFrameAll(KeyFrameThread *thread,
387         KeyFrameWindow *window, int x, int y)
388  : BC_CheckBox(x, y, thread->mwindow->session->keyframedialog_all, 
389         _("Apply to all selected keyframes"))
390 {
391         this->thread = thread;
392         this->window = window;
393 }
394
395 int KeyFrameAll::handle_event()
396 {
397         thread->mwindow->session->keyframedialog_all = get_value();
398         return 1;
399 }
400
401 KeyFrameParamsOK::KeyFrameParamsOK(KeyFrameThread *thread, KeyFrameWindow *window)
402  : BC_OKButton(window)
403 {
404         this->thread = thread;
405         this->window = window;
406 }
407
408 int KeyFrameParamsOK::keypress_event()
409 {
410         if( get_keypress() == RETURN ) {
411                 thread->apply_value();
412                 return 1;
413         }
414         return 0;
415 }
416