add system build to autoconf/automake
[goodguy/history.git] / cinelerra-5.1 / cinelerra / batchrender.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2011 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 "asset.h"
23 #include "batchrender.h"
24 #include "bcdisplayinfo.h"
25 #include "bcsignals.h"
26 #include "confirmsave.h"
27 #include "cstrdup.h"
28 #include "bchash.h"
29 #include "edits.h"
30 #include "edit.h"
31 #include "edl.h"
32 #include "edlsession.h"
33 #include "errorbox.h"
34 #include "file.h"
35 #include "filesystem.h"
36 #include "filexml.h"
37 #include "keyframe.h"
38 #include "keys.h"
39 #include "labels.h"
40 #include "language.h"
41 #include "mainerror.h"
42 #include "mainundo.h"
43 #include "mainsession.h"
44 #include "mutex.h"
45 #include "mwindow.h"
46 #include "mwindowgui.h"
47 #include "packagedispatcher.h"
48 #include "packagerenderer.h"
49 #include "plugin.h"
50 #include "pluginset.h"
51 #include "preferences.h"
52 #include "render.h"
53 #include "theme.h"
54 #include "tracks.h"
55 #include "transportque.h"
56 #include "vframe.h"
57
58
59 static const char *list_titles[] =
60 {
61         _("Enabled"),
62         _("Output"),
63         _("EDL"),
64         _("Elapsed")
65 };
66
67 static int list_widths[] =
68 {
69         50,
70         100,
71         200,
72         100
73 };
74
75 BatchRenderMenuItem::BatchRenderMenuItem(MWindow *mwindow)
76  : BC_MenuItem(_("Batch Render..."), _("Shift-B"), 'B')
77 {
78         set_shift(1);
79         this->mwindow = mwindow;
80 }
81
82 int BatchRenderMenuItem::handle_event()
83 {
84         mwindow->batch_render->start();
85         return 1;
86 }
87
88
89
90
91
92
93
94
95 BatchRenderJob::BatchRenderJob(Preferences *preferences)
96 {
97         this->preferences = preferences;
98         asset = new Asset;
99         edl_path[0] = 0;
100         strategy = 0;
101         enabled = 1;
102         elapsed = 0;
103 }
104
105 BatchRenderJob::~BatchRenderJob()
106 {
107         asset->Garbage::remove_user();
108 }
109
110 void BatchRenderJob::copy_from(BatchRenderJob *src)
111 {
112         asset->copy_from(src->asset, 0);
113         strcpy(edl_path, src->edl_path);
114         strategy = src->strategy;
115         enabled = src->enabled;
116         elapsed = 0;
117 }
118
119 void BatchRenderJob::load(FileXML *file)
120 {
121         int result = 0;
122
123         edl_path[0] = 0;
124         file->tag.get_property("EDL_PATH", edl_path);
125         strategy = file->tag.get_property("STRATEGY", strategy);
126         enabled = file->tag.get_property("ENABLED", enabled);
127         elapsed = file->tag.get_property("ELAPSED", elapsed);
128         fix_strategy();
129
130         result = file->read_tag();
131         if(!result)
132         {
133                 if(file->tag.title_is("ASSET"))
134                 {
135                         file->tag.get_property("SRC", asset->path);
136                         asset->read(file, 0);
137 // The compression parameters are stored in the defaults to reduce
138 // coding maintenance.  The defaults must now be stuffed into the XML for
139 // unique storage.
140                         BC_Hash defaults;
141                         defaults.load_string(file->read_text());
142                         asset->load_defaults(&defaults,
143                                 "",
144                                 0,
145                                 1,
146                                 0,
147                                 0,
148                                 0);
149                 }
150         }
151 }
152
153 void BatchRenderJob::save(FileXML *file)
154 {
155         file->tag.set_property("EDL_PATH", edl_path);
156         file->tag.set_property("STRATEGY", strategy);
157         file->tag.set_property("ENABLED", enabled);
158         file->tag.set_property("ELAPSED", elapsed);
159         file->append_tag();
160         file->append_newline();
161         asset->write(file,
162                 0,
163                 "");
164
165 // The compression parameters are stored in the defaults to reduce
166 // coding maintenance.  The defaults must now be stuffed into the XML for
167 // unique storage.
168         BC_Hash defaults;
169         asset->save_defaults(&defaults,
170                 "",
171                 0,
172                 1,
173                 0,
174                 0,
175                 0);
176         char *string;
177         defaults.save_string(string);
178         file->append_text(string);
179         free(string);
180         file->tag.set_title("/JOB");
181         file->append_tag();
182         file->append_newline();
183 }
184
185 void BatchRenderJob::fix_strategy()
186 {
187         strategy = Render::fix_strategy(strategy, preferences->use_renderfarm);
188 }
189
190
191
192
193
194
195
196
197
198
199 BatchRenderThread::BatchRenderThread(MWindow *mwindow)
200  : BC_DialogThread()
201 {
202         this->mwindow = mwindow;
203         current_job = 0;
204         rendering_job = -1;
205         is_rendering = 0;
206         default_job = 0;
207         boot_defaults = 0;
208         preferences = 0;
209         render = 0;
210         file_entries = 0;
211 }
212
213 BatchRenderThread::BatchRenderThread()
214  : BC_DialogThread()
215 {
216         mwindow = 0;
217         current_job = 0;
218         rendering_job = -1;
219         is_rendering = 0;
220         default_job = 0;
221         boot_defaults = 0;
222         preferences = 0;
223         render = 0;
224         file_entries = 0;
225 }
226
227 BatchRenderThread::~BatchRenderThread()
228 {
229         close_window();
230         delete boot_defaults;
231         delete preferences;
232         delete render;
233         if( file_entries ) {
234                 file_entries->remove_all_objects();
235                 delete file_entries;
236         }
237 }
238
239 void BatchRenderThread::reset()
240 {
241         current_job = 0;
242         rendering_job = -1;
243         delete default_job;  default_job = 0;
244         jobs.remove_all_objects();
245         if(file_entries) {
246                 file_entries->remove_all_objects();
247                 delete file_entries;  file_entries = 0;
248         }
249 }
250
251 void BatchRenderThread::handle_close_event(int result)
252 {
253 // Save settings
254         char path[BCTEXTLEN];
255         path[0] = 0;
256         save_jobs(path);
257         save_defaults(mwindow->defaults);
258         reset();
259 }
260
261 BC_Window* BatchRenderThread::new_gui()
262 {
263         current_start = 0.0;
264         current_end = 0.0;
265         default_job = new BatchRenderJob(mwindow->preferences);
266
267
268         if(!file_entries)
269         {
270                 file_entries = new ArrayList<BC_ListBoxItem*>;
271                 FileSystem fs;
272                 char string[BCTEXTLEN];
273         // Load current directory
274                 fs.update(getcwd(string, BCTEXTLEN));
275                 for(int i = 0; i < fs.total_files(); i++)
276                 {
277                         file_entries->append(
278                                 new BC_ListBoxItem(
279                                         fs.get_entry(i)->get_name()));
280                 }
281         }
282
283         char path[BCTEXTLEN];
284         path[0] = 0;
285         load_jobs(path, mwindow->preferences);
286         load_defaults(mwindow->defaults);
287         this->gui = new BatchRenderGUI(mwindow,
288                 this,
289                 mwindow->session->batchrender_x,
290                 mwindow->session->batchrender_y,
291                 mwindow->session->batchrender_w,
292                 mwindow->session->batchrender_h);
293         this->gui->create_objects();
294         return this->gui;
295 }
296
297
298 void BatchRenderThread::load_jobs(char *path, Preferences *preferences)
299 {
300         FileXML file;
301         int result = 0;
302
303         jobs.remove_all_objects();
304         if(path[0])
305                 file.read_from_file(path);
306         else
307                 file.read_from_file(create_path(path));
308
309         while(!result)
310         {
311                 if(!(result = file.read_tag()))
312                 {
313                         if(file.tag.title_is("JOB"))
314                         {
315                                 BatchRenderJob *job;
316                                 jobs.append(job = new BatchRenderJob(preferences));
317                                 job->load(&file);
318                         }
319                 }
320         }
321 }
322
323 void BatchRenderThread::save_jobs(char *path)
324 {
325         FileXML file;
326
327         for(int i = 0; i < jobs.total; i++)
328         {
329                 file.tag.set_title("JOB");
330                 jobs.values[i]->save(&file);
331         }
332
333         if(path[0])
334                 file.write_to_file(path);
335         else
336                 file.write_to_file(create_path(path));
337 }
338
339 void BatchRenderThread::load_defaults(BC_Hash *defaults)
340 {
341         if(default_job)
342         {
343                 default_job->asset->load_defaults(defaults,
344                         "BATCHRENDER_",
345                         1,
346                         1,
347                         1,
348                         1,
349                         1);
350                 default_job->fix_strategy();
351         }
352
353         for(int i = 0; i < BATCHRENDER_COLUMNS; i++)
354         {
355                 char string[BCTEXTLEN];
356                 sprintf(string, "BATCHRENDER_COLUMN%d", i);
357                 column_width[i] = defaults->get(string, list_widths[i]);
358         }
359 }
360
361 void BatchRenderThread::save_defaults(BC_Hash *defaults)
362 {
363         if(default_job)
364         {
365                 default_job->asset->save_defaults(defaults,
366                         "BATCHRENDER_",
367                         1,
368                         1,
369                         1,
370                         1,
371                         1);
372                 defaults->update("BATCHRENDER_STRATEGY", default_job->strategy);
373         }
374         for(int i = 0; i < BATCHRENDER_COLUMNS; i++)
375         {
376                 char string[BCTEXTLEN];
377                 sprintf(string, "BATCHRENDER_COLUMN%d", i);
378                 defaults->update(string, column_width[i]);
379         }
380 //      defaults->update("BATCHRENDER_JOB", current_job);
381         if(mwindow)
382                 mwindow->save_defaults();
383         else
384                 defaults->save();
385 }
386
387 char* BatchRenderThread::create_path(char *string)
388 {
389         FileSystem fs;
390         sprintf(string, "%s/", File::get_config_path());
391         fs.complete_path(string);
392         strcat(string, BATCH_PATH);
393         return string;
394 }
395
396 void BatchRenderThread::new_job()
397 {
398         BatchRenderJob *result = new BatchRenderJob(mwindow->preferences);
399         result->copy_from(get_current_job());
400         jobs.append(result);
401         current_job = jobs.total - 1;
402         gui->create_list(1);
403         gui->change_job();
404 }
405
406 void BatchRenderThread::delete_job()
407 {
408         if(current_job < jobs.total && current_job >= 0)
409         {
410                 jobs.remove_object_number(current_job);
411                 if(current_job > 0) current_job--;
412                 gui->create_list(1);
413                 gui->change_job();
414         }
415 }
416
417 void BatchRenderThread::use_current_edl()
418 {
419 // printf("BatchRenderThread::use_current_edl %d %p %s\n",
420 // __LINE__,
421 // mwindow->edl->path,
422 // mwindow->edl->path);
423
424         strcpy(get_current_edl(), mwindow->edl->path);
425         gui->create_list(1);
426         gui->edl_path_text->update(get_current_edl());
427 }
428
429 void BatchRenderThread::update_selected_edl()
430 {
431         FileXML xml_file;
432         char *path = get_current_edl();
433         EDL *edl = mwindow->edl;
434         edl->save_xml(&xml_file, path, 0, 0);
435         xml_file.terminate_string();
436         if( xml_file.write_to_file(path) ) {
437                 char msg[BCTEXTLEN];
438                 sprintf(msg, _("Unable to save: %s"), path);
439                 MainError::show_error(msg);
440         }
441 }
442
443 BatchRenderJob* BatchRenderThread::get_current_job()
444 {
445         BatchRenderJob *result;
446         if(current_job >= jobs.total || current_job < 0)
447         {
448                 result = default_job;
449         }
450         else
451         {
452                 result = jobs.values[current_job];
453         }
454         return result;
455 }
456
457
458 Asset* BatchRenderThread::get_current_asset()
459 {
460         return get_current_job()->asset;
461 }
462
463 char* BatchRenderThread::get_current_edl()
464 {
465         return get_current_job()->edl_path;
466 }
467
468
469 // Test EDL files for existence
470 int BatchRenderThread::test_edl_files()
471 {
472         for(int i = 0; i < jobs.total; i++)
473         {
474                 if(jobs.values[i]->enabled)
475                 {
476                         const char *path = jobs.values[i]->edl_path;
477                         if( *path == '@' ) ++path;
478                         FILE *fd = fopen(path, "r");
479                         if(!fd)
480                         {
481                                 char string[BCTEXTLEN];
482                                 sprintf(string, _("EDL %s not found.\n"), jobs.values[i]->edl_path);
483                                 if(mwindow)
484                                 {
485                                         ErrorBox error_box(_(PROGRAM_NAME ": Error"),
486                                                 mwindow->gui->get_abs_cursor_x(1),
487                                                 mwindow->gui->get_abs_cursor_y(1));
488                                         error_box.create_objects(string);
489                                         error_box.run_window();
490                                         gui->button_enable();
491                                 }
492                                 else
493                                 {
494                                         fprintf(stderr,
495                                                 "%s",
496                                                 string);
497                                 }
498
499                                 is_rendering = 0;
500                                 return 1;
501                         }
502                         else
503                         {
504                                 fclose(fd);
505                         }
506                 }
507         }
508         return 0;
509 }
510
511 void BatchRenderThread::calculate_dest_paths(ArrayList<char*> *paths,
512         Preferences *preferences)
513 {
514         for(int i = 0; i < jobs.total; i++)
515         {
516                 BatchRenderJob *job = jobs.values[i];
517                 if(job->enabled && *job->edl_path != '@')
518                 {
519                         PackageDispatcher *packages = new PackageDispatcher;
520
521 // Load EDL
522                         TransportCommand *command = new TransportCommand;
523                         FileXML *file = new FileXML;
524                         file->read_from_file(job->edl_path);
525
526 // Use command to calculate range.
527                         command->command = NORMAL_FWD;
528                         command->get_edl()->load_xml(file,
529                                 LOAD_ALL);
530                         command->change_type = CHANGE_ALL;
531                         command->set_playback_range();
532                         command->playback_range_adjust_inout();
533
534 // Create test packages
535                         packages->create_packages(mwindow,
536                                 command->get_edl(),
537                                 preferences,
538                                 job->strategy,
539                                 job->asset,
540                                 command->start_position,
541                                 command->end_position,
542                                 0);
543
544 // Append output paths allocated to total
545                         packages->get_package_paths(paths);
546
547 // Delete package harness
548                         delete packages;
549                         delete command;
550                         delete file;
551                 }
552         }
553 }
554
555
556 void BatchRenderThread::start_rendering(char *config_path,
557         char *batch_path)
558 {
559         BC_Hash *boot_defaults;
560         Preferences *preferences;
561         Render *render;
562         BC_Signals *signals = new BC_Signals;
563         // XXX the above stuff is leaked,
564 //PRINT_TRACE
565 // Initialize stuff which MWindow does.
566         signals->initialize();
567         MWindow::init_defaults(boot_defaults, config_path);
568         load_defaults(boot_defaults);
569         preferences = new Preferences;
570         preferences->load_defaults(boot_defaults);
571         MWindow::init_plugins(0, preferences);
572         char font_path[BCTEXTLEN];
573         strcpy(font_path, preferences->plugin_dir);
574         strcat(font_path, "/" FONT_SEARCHPATH);
575         BC_Resources::init_fontconfig(font_path);
576         BC_WindowBase::get_resources()->vframe_shm = 1;
577
578 //PRINT_TRACE
579         load_jobs(batch_path, preferences);
580         save_jobs(batch_path);
581         save_defaults(boot_defaults);
582
583 //PRINT_TRACE
584 // Test EDL files for existence
585         if(test_edl_files()) return;
586
587 //PRINT_TRACE
588
589 // Predict all destination paths
590         ArrayList<char*> paths;
591         paths.set_array_delete();
592         calculate_dest_paths(&paths, preferences);
593
594 //PRINT_TRACE
595         int result = ConfirmSave::test_files(0, &paths);
596         paths.remove_all_objects();
597 // Abort on any existing file because it's so hard to set this up.
598         if(result) return;
599
600 //PRINT_TRACE
601         render = new Render(0);
602 //PRINT_TRACE
603         render->start_batches(&jobs,
604                 boot_defaults,
605                 preferences);
606 //PRINT_TRACE
607 }
608
609 void BatchRenderThread::start_rendering()
610 {
611         if(is_rendering) return;
612
613         is_rendering = 1;
614         char path[BCTEXTLEN];
615         path[0] = 0;
616         save_jobs(path);
617         save_defaults(mwindow->defaults);
618         gui->button_disable();
619
620 // Test EDL files for existence
621         if(test_edl_files()) return;
622
623 // Predict all destination paths
624         ArrayList<char*> paths;
625         calculate_dest_paths(&paths,
626                 mwindow->preferences);
627
628 // Test destination files for overwrite
629         int result = ConfirmSave::test_files(mwindow, &paths);
630         paths.remove_all_objects();
631
632 // User cancelled
633         if(result)
634         {
635                 is_rendering = 0;
636                 gui->button_enable();
637                 return;
638         }
639
640         mwindow->render->start_batches(&jobs);
641 }
642
643 void BatchRenderThread::stop_rendering()
644 {
645         if(!is_rendering) return;
646         mwindow->render->stop_operation();
647         is_rendering = 0;
648 }
649
650 void BatchRenderThread::update_active(int number)
651 {
652         gui->lock_window("BatchRenderThread::update_active");
653         if(number >= 0)
654         {
655                 current_job = number;
656                 rendering_job = number;
657         }
658         else
659         {
660                 rendering_job = -1;
661                 is_rendering = 0;
662         }
663         gui->create_list(1);
664         gui->unlock_window();
665 }
666
667 void BatchRenderThread::update_done(int number,
668         int create_list,
669         double elapsed_time)
670 {
671         gui->lock_window("BatchRenderThread::update_done");
672         if(number < 0)
673         {
674                 gui->button_enable();
675         }
676         else
677         {
678                 jobs.values[number]->enabled = 0;
679                 jobs.values[number]->elapsed = elapsed_time;
680                 if(create_list) gui->create_list(1);
681         }
682         gui->unlock_window();
683 }
684
685 void BatchRenderThread::move_batch(int src, int dst)
686 {
687         BatchRenderJob *src_job = jobs.values[src];
688         if(dst < 0) dst = jobs.total - 1;
689
690         if(dst != src)
691         {
692                 for(int i = src; i < jobs.total - 1; i++)
693                         jobs.values[i] = jobs.values[i + 1];
694 //              if(dst > src) dst--;
695                 for(int i = jobs.total - 1; i > dst; i--)
696                         jobs.values[i] = jobs.values[i - 1];
697                 jobs.values[dst] = src_job;
698                 gui->create_list(1);
699         }
700 }
701
702
703
704
705
706
707
708 BatchRenderGUI::BatchRenderGUI(MWindow *mwindow,
709         BatchRenderThread *thread,
710         int x,
711         int y,
712         int w,
713         int h)
714  : BC_Window(_(PROGRAM_NAME ": Batch Render"),
715         x,
716         y,
717         w,
718         h,
719         50,
720         50,
721         1,
722         0,
723         1)
724 {
725         this->mwindow = mwindow;
726         this->thread = thread;
727 }
728
729 BatchRenderGUI::~BatchRenderGUI()
730 {
731         lock_window("BatchRenderGUI::~BatchRenderGUI");
732         delete format_tools;
733         unlock_window();
734 }
735
736
737 void BatchRenderGUI::create_objects()
738 {
739         lock_window("BatchRenderGUI::create_objects");
740         mwindow->theme->get_batchrender_sizes(this, get_w(), get_h());
741         create_list(0);
742
743         int x = mwindow->theme->batchrender_x1;
744         int y = 5;
745         int x1 = x, x2 = get_w()/2 + 10; // mwindow->theme->batchrender_x2;
746         int y1 = 5, y2 = 5;
747
748 // output file
749         add_subwindow(output_path_title = new BC_Title(x1, y1, _("Output path:")));
750         y1 += output_path_title->get_h() + mwindow->theme->widget_border;
751
752         format_tools = new BatchFormat(mwindow, this, thread->get_current_asset());
753         format_tools->set_w(get_w() / 2);
754         format_tools->create_objects(x1, y1, 1, 1, 1, 1, 0, 1, 0, 0,
755                         &thread->get_current_job()->strategy, 0); 
756
757 // input EDL
758         add_subwindow(edl_path_title = new BC_Title(x2, y2, _("EDL Path:")));
759         y2 += edl_path_title->get_h() + mwindow->theme->widget_border;
760         
761         x = x2;  y = y2;
762         add_subwindow(edl_path_text = new BatchRenderEDLPath( thread,
763                 x, y, get_w()-x - 40, thread->get_current_edl())); 
764         x =  x2 + edl_path_text->get_w();
765         add_subwindow(edl_path_browse = new BrowseButton(
766                 mwindow, this, edl_path_text, x, y, thread->get_current_edl(),
767                 _("Input EDL"), _("Select an EDL to load:"), 0));
768         y2 = y + edl_path_browse->get_h() + mwindow->theme->widget_border;
769
770         x = x2;  y = y2;
771         add_subwindow(update_selected_edl = new BatchRenderUpdateEDL(thread, x, y));
772         y += update_selected_edl->get_h() + mwindow->theme->widget_border;
773         add_subwindow(use_current_edl = new BatchRenderCurrentEDL(thread, x, y));
774         y += use_current_edl->get_h() + mwindow->theme->widget_border;
775         if( !mwindow->edl || !mwindow->edl->path[0] ) use_current_edl->disable();
776         add_subwindow(new_batch = new BatchRenderNew(thread, x, y));
777         x += new_batch->get_w() + mwindow->theme->widget_border;
778         add_subwindow(delete_batch = new BatchRenderDelete(thread, x, y));
779         x = x2;  y += delete_batch->get_h() + mwindow->theme->widget_border;
780         add_subwindow(savelist_batch = new BatchRenderSaveList(thread, x, y));
781         x += savelist_batch->get_w() + mwindow->theme->widget_border;
782         add_subwindow(loadlist_batch = new BatchRenderLoadList(thread, x, y));
783         y2 = y + loadlist_batch->get_h() + mwindow->theme->widget_border;
784         if( y2 > y1 ) y1 = y2;
785         x = mwindow->theme->batchrender_x1, y = y1;
786
787         add_subwindow(list_title = new BC_Title(x, y, _("Batches to render:")));
788         y += list_title->get_h() + mwindow->theme->widget_border;
789         y1 = get_h();
790         y1 -= 15 + BC_GenericButton::calculate_h() + mwindow->theme->widget_border;
791         add_subwindow(batch_list = new BatchRenderList(thread, x, y,
792                 get_w() - x - 10, y1 - y));
793         y += batch_list->get_h() + mwindow->theme->widget_border;
794
795         add_subwindow(start_button = new BatchRenderStart(thread, x, y));
796         x = get_w() / 2 - BC_GenericButton::calculate_w(this, _("Stop")) / 2;
797         add_subwindow(stop_button = new BatchRenderStop(thread, x, y));
798         x = get_w() - BC_GenericButton::calculate_w(this, _("Close")) - 10;
799         add_subwindow(cancel_button = new BatchRenderCancel(thread, x, y));
800
801         show_window(1);
802         unlock_window();
803 }
804
805 void BatchRenderGUI::button_disable()
806 {
807         new_batch->disable();
808         delete_batch->disable();
809         use_current_edl->disable();
810         update_selected_edl->disable();
811 }
812
813 void BatchRenderGUI::button_enable()
814 {
815         new_batch->enable();
816         delete_batch->enable();
817         if( mwindow->edl && mwindow->edl->path[0] )
818                 use_current_edl->enable();
819         update_selected_edl->enable();
820 }
821
822 int BatchRenderGUI::resize_event(int w, int h)
823 {
824         mwindow->session->batchrender_w = w;
825         mwindow->session->batchrender_h = h;
826         mwindow->theme->get_batchrender_sizes(this, w, h);
827
828         int x = mwindow->theme->batchrender_x1;
829         int y = 5;
830         int x1 = x, x2 = get_w()/2 + 10; // mwindow->theme->batchrender_x2;
831         int y1 = 5, y2 = 5;
832
833 // output file
834         output_path_title->reposition_window(x1, y1);
835         y1 += output_path_title->get_h() + mwindow->theme->widget_border;
836         format_tools->reposition_window(x1, y1);
837
838 // input EDL
839         x = x2, y = y2;
840         edl_path_title->reposition_window(x, y);
841         y += edl_path_title->get_h() + mwindow->theme->widget_border;
842         edl_path_text->reposition_window(x, y, w - x - 40);
843         x += edl_path_text->get_w();
844         edl_path_browse->reposition_window(x, y);
845         y2 = y + edl_path_browse->get_h() + mwindow->theme->widget_border;
846
847         x = x2;  y = y2;
848         update_selected_edl->reposition_window(x, y);
849         y += update_selected_edl->get_h() + mwindow->theme->widget_border;
850         use_current_edl->reposition_window(x, y);
851         y += use_current_edl->get_h() + mwindow->theme->widget_border;
852         new_batch->reposition_window(x, y);
853         x += new_batch->get_w() + mwindow->theme->widget_border;
854         delete_batch->reposition_window(x, y);
855
856         x = x2;  y += delete_batch->get_h() + mwindow->theme->widget_border;
857         savelist_batch->reposition_window(x, y);
858         x += savelist_batch->get_w() + mwindow->theme->widget_border;
859         loadlist_batch->reposition_window(x, y);
860         y += loadlist_batch->get_h() + mwindow->theme->widget_border;
861
862         y1 = 15 + BC_GenericButton::calculate_h() + mwindow->theme->widget_border;
863         y2 = get_h() - y1 - batch_list->get_h();
864         y2 -= list_title->get_h() + mwindow->theme->widget_border;
865
866         x = mwindow->theme->batchrender_x1;  y = y2;
867         list_title->reposition_window(x, y);
868         y += list_title->get_h() + mwindow->theme->widget_border;
869         batch_list->reposition_window(x, y, w - x - 10, h - y - y1);
870         y += batch_list->get_h() + mwindow->theme->widget_border;
871
872         start_button->reposition_window(x, y);
873         x = w / 2 - stop_button->get_w() / 2;
874         stop_button->reposition_window(x, y);
875         x = w - cancel_button->get_w() - 10;
876         cancel_button->reposition_window(x, y);
877         return 1;
878 }
879
880 int BatchRenderGUI::translation_event()
881 {
882         mwindow->session->batchrender_x = get_x();
883         mwindow->session->batchrender_y = get_y();
884         return 1;
885 }
886
887 int BatchRenderGUI::close_event()
888 {
889 // Stop batch rendering
890         unlock_window();
891         thread->stop_rendering();
892         lock_window("BatchRenderGUI::close_event");
893         set_done(1);
894         return 1;
895 }
896
897 void BatchRenderGUI::create_list(int update_widget)
898 {
899         for(int i = 0; i < BATCHRENDER_COLUMNS; i++)
900         {
901                 list_columns[i].remove_all_objects();
902         }
903
904         for(int i = 0; i < thread->jobs.total; i++)
905         {
906                 BatchRenderJob *job = thread->jobs.values[i];
907                 char string[BCTEXTLEN];
908                 BC_ListBoxItem *enabled = new BC_ListBoxItem(job->enabled ?
909                         (char*)"X" :
910                         (char*)" ");
911                 BC_ListBoxItem *item1 = new BC_ListBoxItem(job->asset->path);
912                 BC_ListBoxItem *item2 = new BC_ListBoxItem(job->edl_path);
913                 BC_ListBoxItem *item3;
914                 if(job->elapsed)
915                         item3 = new BC_ListBoxItem(
916                                 Units::totext(string,
917                                         job->elapsed,
918                                         TIME_HMS2));
919                 else
920                         item3 = new BC_ListBoxItem(_("Unknown"));
921                 list_columns[0].append(enabled);
922                 list_columns[1].append(item1);
923                 list_columns[2].append(item2);
924                 list_columns[3].append(item3);
925                 if(i == thread->current_job)
926                 {
927                         enabled->set_selected(1);
928                         item1->set_selected(1);
929                         item2->set_selected(1);
930                         item3->set_selected(1);
931                 }
932                 if(i == thread->rendering_job)
933                 {
934                         enabled->set_color(RED);
935                         item1->set_color(RED);
936                         item2->set_color(RED);
937                         item3->set_color(RED);
938                 }
939         }
940
941         if(update_widget)
942         {
943                 batch_list->update(list_columns,
944                                                 list_titles,
945                                                 thread->column_width,
946                                                 BATCHRENDER_COLUMNS,
947                                                 batch_list->get_xposition(),
948                                                 batch_list->get_yposition(),
949                                                 batch_list->get_highlighted_item(),  // Flat index of item cursor is over
950                                                 1,     // set all autoplace flags to 1
951                                                 1);
952         }
953 }
954
955 void BatchRenderGUI::change_job()
956 {
957         BatchRenderJob *job = thread->get_current_job();
958         format_tools->update(job->asset, &job->strategy);
959         edl_path_text->update(job->edl_path);
960 }
961
962
963
964
965
966
967
968
969 BatchFormat::BatchFormat(MWindow *mwindow,
970                         BatchRenderGUI *gui,
971                         Asset *asset)
972  : FormatTools(mwindow, gui, asset)
973 {
974         this->gui = gui;
975         this->mwindow = mwindow;
976 }
977
978 BatchFormat::~BatchFormat()
979 {
980 }
981
982
983 int BatchFormat::handle_event()
984 {
985         gui->create_list(1);
986         return 1;
987 }
988
989
990
991
992
993
994
995
996
997
998
999 BatchRenderEDLPath::BatchRenderEDLPath(BatchRenderThread *thread,
1000         int x,
1001         int y,
1002         int w,
1003         char *text)
1004  : BC_TextBox(x,
1005                 y,
1006                 w,
1007                 1,
1008                 text)
1009 {
1010         this->thread = thread;
1011 }
1012
1013
1014 int BatchRenderEDLPath::handle_event()
1015 {
1016 // Suggestions
1017         calculate_suggestions(thread->file_entries);
1018
1019         strcpy(thread->get_current_edl(), get_text());
1020         thread->gui->create_list(1);
1021         return 1;
1022 }
1023
1024
1025
1026
1027
1028
1029 BatchRenderNew::BatchRenderNew(BatchRenderThread *thread,
1030         int x,
1031         int y)
1032  : BC_GenericButton(x, y, _("New"))
1033 {
1034         this->thread = thread;
1035 }
1036
1037 int BatchRenderNew::handle_event()
1038 {
1039         thread->new_job();
1040         return 1;
1041 }
1042
1043 BatchRenderDelete::BatchRenderDelete(BatchRenderThread *thread,
1044         int x,
1045         int y)
1046  : BC_GenericButton(x, y, _("Delete"))
1047 {
1048         this->thread = thread;
1049 }
1050
1051 int BatchRenderDelete::handle_event()
1052 {
1053         thread->delete_job();
1054         return 1;
1055 }
1056
1057
1058
1059 BatchRenderSaveList::BatchRenderSaveList(BatchRenderThread *thread,
1060         int x,
1061         int y)
1062  : BC_GenericButton(x, y, _("Save List"))
1063 {
1064         this->thread = thread;
1065         set_tooltip(_("Save a Batch Render List"));
1066         gui = 0;
1067         startup_lock = new Mutex("BatchRenderSaveList::startup_lock");
1068 }
1069
1070 BatchRenderSaveList::~BatchRenderSaveList()
1071 {
1072         startup_lock->lock("BatchRenderSaveList::~BrowseButton");
1073         if(gui)
1074         {
1075                 gui->lock_window();
1076                 gui->set_done(1);
1077                 gui->unlock_window();
1078         }
1079         startup_lock->unlock();
1080         Thread::join();
1081         delete startup_lock;
1082 }
1083
1084 int BatchRenderSaveList::handle_event()
1085 {
1086         if(Thread::running())
1087         {
1088                 if(gui)
1089                 {
1090                         gui->lock_window();
1091                         gui->raise_window();
1092                         gui->unlock_window();
1093                 }
1094                 return 1;
1095         }
1096         startup_lock->lock("BatchRenderSaveList::handle_event 1");
1097         Thread::start();
1098         startup_lock->lock("BatchRenderSaveList::handle_event 2");
1099         startup_lock->unlock();
1100         return 1;
1101 }
1102
1103 void BatchRenderSaveList::run()
1104 {
1105         char default_path[BCTEXTLEN];
1106         sprintf(default_path, "~");
1107         BC_FileBox filewindow(100,
1108                               100,
1109                               this->thread->mwindow->defaults->get("DEFAULT_BATCHLOADPATH", default_path),
1110                               _("Save Batch Render List"),
1111                               _("Enter a Batch Render filename to save as:"),
1112                               0,
1113                               0,
1114                               0,
1115                               0);
1116
1117         gui = &filewindow;
1118
1119         startup_lock->unlock();
1120         filewindow.create_objects();
1121
1122         int result2 = filewindow.run_window();
1123
1124         if(!result2)
1125         {
1126                 this->thread->save_jobs(filewindow.get_submitted_path());
1127                 this->thread->mwindow->defaults->update("DEFAULT_BATCHLOADPATH", filewindow.get_submitted_path());
1128         }
1129
1130         this->thread->gui->flush();
1131         startup_lock->lock("BatchRenderLoadList::run");
1132         gui = 0;
1133         startup_lock->unlock();
1134 }
1135
1136 int BatchRenderSaveList::keypress_event() {
1137         if (get_keypress() == 's' ||
1138             get_keypress() == 'S') return handle_event();
1139         return 0;
1140 }
1141
1142
1143
1144
1145 BatchRenderLoadList::BatchRenderLoadList(BatchRenderThread *thread,
1146         int x,
1147         int y)
1148   : BC_GenericButton(x, y, _("Load List")),
1149     Thread()
1150 {
1151         this->thread = thread;
1152         set_tooltip(_("Load a previously saved Batch Render List"));
1153         gui = 0;
1154         startup_lock = new Mutex("BatchRenderLoadList::startup_lock");
1155 }
1156
1157 BatchRenderLoadList::~BatchRenderLoadList()
1158 {
1159         startup_lock->lock("BatchRenderLoadList::~BrowseButton");
1160         if(gui)
1161         {
1162                 gui->lock_window();
1163                 gui->set_done(1);
1164                 gui->unlock_window();
1165         }
1166         startup_lock->unlock();
1167         Thread::join();
1168         delete startup_lock;
1169 }
1170
1171 int BatchRenderLoadList::handle_event()
1172 {
1173         if(Thread::running())
1174         {
1175                 if(gui)
1176                 {
1177                         gui->lock_window();
1178                         gui->raise_window();
1179                         gui->unlock_window();
1180                 }
1181                 return 1;
1182         }
1183         startup_lock->lock("BatchRenderLoadList::handle_event 1");
1184         Thread::start();
1185         startup_lock->lock("BatchRenderLoadList::handle_event 2");
1186         startup_lock->unlock();
1187         return 1;
1188 }
1189
1190 void BatchRenderLoadList::run()
1191 {
1192         char default_path[BCTEXTLEN];
1193         sprintf(default_path, "~");
1194         BC_FileBox filewindow(100,
1195                               100,
1196                               this->thread->mwindow->defaults->get("DEFAULT_BATCHLOADPATH", default_path),
1197                               _("Load Batch Render List"),
1198                               _("Enter a Batch Render filename to load from:"),
1199                               0,
1200                               0,
1201                               0,
1202                               0);
1203
1204         gui = &filewindow;
1205
1206         startup_lock->unlock();
1207         filewindow.create_objects();
1208
1209         int result2 = filewindow.run_window();
1210
1211         if(!result2)
1212         {
1213                 this->thread->load_jobs(filewindow.get_submitted_path(),this->thread->mwindow->preferences);
1214                 this->thread->gui->create_list(1);
1215                 this->thread->mwindow->defaults->update("DEFAULT_BATCHLOADPATH", filewindow.get_submitted_path());
1216         }
1217
1218         this->thread->gui->flush();
1219         startup_lock->lock("BatchRenderLoadList::run");
1220         gui = 0;
1221         startup_lock->unlock();
1222 }
1223
1224 int BatchRenderLoadList::keypress_event() {
1225         if (get_keypress() == 'o' ||
1226             get_keypress() == 'O') return handle_event();
1227         return 0;
1228 }
1229
1230 BatchRenderCurrentEDL::BatchRenderCurrentEDL(BatchRenderThread *thread,
1231         int x,
1232         int y)
1233  : BC_GenericButton(x, y, _("Use Current EDL"))
1234 {
1235         this->thread = thread;
1236 }
1237
1238 int BatchRenderCurrentEDL::handle_event()
1239 {
1240         thread->use_current_edl();
1241         return 1;
1242 }
1243
1244 BatchRenderUpdateEDL::BatchRenderUpdateEDL(BatchRenderThread *thread,
1245         int x,
1246         int y)
1247  : BC_GenericButton(x, y, _("Save to EDL Path"))
1248 {
1249         this->thread = thread;
1250 }
1251
1252 int BatchRenderUpdateEDL::handle_event()
1253 {
1254         thread->update_selected_edl();
1255         return 1;
1256 }
1257
1258
1259
1260
1261 BatchRenderList::BatchRenderList(BatchRenderThread *thread,
1262         int x,
1263         int y,
1264         int w,
1265         int h)
1266  : BC_ListBox(x,
1267         y,
1268         w,
1269         h,
1270         LISTBOX_TEXT,
1271         thread->gui->list_columns,
1272         list_titles,
1273         thread->column_width,
1274         BATCHRENDER_COLUMNS,
1275         0,
1276         0,
1277         LISTBOX_SINGLE,
1278         ICON_LEFT,
1279         1)
1280 {
1281         this->thread = thread;
1282         dragging_item = 0;
1283         set_process_drag(0);
1284 }
1285
1286 int BatchRenderList::handle_event()
1287 {
1288         return 1;
1289 }
1290
1291 int BatchRenderList::selection_changed()
1292 {
1293         thread->current_job = get_selection_number(0, 0);
1294         thread->gui->change_job();
1295         if(get_cursor_x() < thread->column_width[0])
1296         {
1297                 BatchRenderJob *job = thread->get_current_job();
1298                 job->enabled = !job->enabled;
1299                 thread->gui->create_list(1);
1300         }
1301         return 1;
1302 }
1303
1304 int BatchRenderList::column_resize_event()
1305 {
1306         for(int i = 0; i < BATCHRENDER_COLUMNS; i++)
1307         {
1308                 thread->column_width[i] = get_column_width(i);
1309         }
1310         return 1;
1311 }
1312
1313 int BatchRenderList::drag_start_event()
1314 {
1315         if(BC_ListBox::drag_start_event())
1316         {
1317                 dragging_item = 1;
1318                 return 1;
1319         }
1320
1321         return 0;
1322 }
1323
1324 int BatchRenderList::drag_motion_event()
1325 {
1326         if(BC_ListBox::drag_motion_event())
1327         {
1328                 return 1;
1329         }
1330         return 0;
1331 }
1332
1333 int BatchRenderList::drag_stop_event()
1334 {
1335         if(dragging_item)
1336         {
1337                 int src = get_selection_number(0, 0);
1338                 int dst = get_highlighted_item();
1339                 if(src != dst)
1340                 {
1341                         thread->move_batch(src, dst);
1342                 }
1343                 BC_ListBox::drag_stop_event();
1344         }
1345         return 0;
1346 }
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360 BatchRenderStart::BatchRenderStart(BatchRenderThread *thread,
1361         int x,
1362         int y)
1363  : BC_GenericButton(x,
1364         y,
1365         _("Start"))
1366 {
1367         this->thread = thread;
1368 }
1369
1370 int BatchRenderStart::handle_event()
1371 {
1372         thread->start_rendering();
1373         return 1;
1374 }
1375
1376 BatchRenderStop::BatchRenderStop(BatchRenderThread *thread,
1377         int x,
1378         int y)
1379  : BC_GenericButton(x,
1380         y,
1381         _("Stop"))
1382 {
1383         this->thread = thread;
1384 }
1385
1386 int BatchRenderStop::handle_event()
1387 {
1388         unlock_window();
1389         thread->stop_rendering();
1390         lock_window("BatchRenderStop::handle_event");
1391         return 1;
1392 }
1393
1394
1395 BatchRenderCancel::BatchRenderCancel(BatchRenderThread *thread,
1396         int x,
1397         int y)
1398  : BC_GenericButton(x,
1399         y,
1400         _("Close"))
1401 {
1402         this->thread = thread;
1403 }
1404
1405 int BatchRenderCancel::handle_event()
1406 {
1407         unlock_window();
1408         thread->stop_rendering();
1409         lock_window("BatchRenderCancel::handle_event");
1410         thread->gui->set_done(1);
1411         return 1;
1412 }
1413
1414 int BatchRenderCancel::keypress_event()
1415 {
1416         if(get_keypress() == ESC)
1417         {
1418                 unlock_window();
1419                 thread->stop_rendering();
1420                 lock_window("BatchRenderCancel::keypress_event");
1421                 thread->gui->set_done(1);
1422                 return 1;
1423         }
1424         return 0;
1425 }
1426