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