no longer need ffmpeg patch0 which was for Termux
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / formattools.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2010-2013 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 "bcsignals.h"
24 #include "clip.h"
25 #include "guicast.h"
26 #include "file.h"
27 #include "filesystem.h"
28 #include "formattools.h"
29 #include "language.h"
30 #ifdef HAVE_DV
31 #include "libdv.h"
32 #endif
33 #include "libmjpeg.h"
34 #include "maxchannels.h"
35 #include "mwindow.h"
36 #include "preferences.h"
37 #include "theme.h"
38 #include "videodevice.inc"
39 #include <string.h>
40 #include <unistd.h>
41 #include <ctype.h>
42
43
44 FormatTools::FormatTools(MWindow *mwindow,
45                                 BC_WindowBase *window,
46                                 Asset *asset)
47 {
48         this->mwindow = mwindow;
49         this->window = window;
50         this->asset = asset;
51
52         aparams_button = 0;
53         vparams_button = 0;
54         aparams_thread = 0;
55         vparams_thread = 0;
56         audio_switch = 0;
57         video_switch = 0;
58         path_textbox = 0;
59         path_button = 0;
60         path_recent = 0;
61         format_title = 0;
62         format_button = 0;
63         format_text = 0;
64         audio_title = 0;
65         video_title = 0;
66         labeled_files = 0;
67         w = window->get_w();
68
69         recording = 0;
70         use_brender = 0;
71         do_audio = 0;
72         do_video = 0;
73         prompt_audio = 0;
74         prompt_audio_channels = 0;
75         prompt_video = 0;
76         prompt_video_compression = 0;
77         file_per_label = 0;
78         locked_compressor = 0;
79         video_driver = 0;
80 }
81
82 FormatTools::~FormatTools()
83 {
84         delete path_recent;
85 SET_TRACE
86         delete path_button;
87 SET_TRACE
88         delete path_textbox;
89 SET_TRACE
90         delete format_button;
91 SET_TRACE
92
93         if(aparams_button) delete aparams_button;
94 SET_TRACE
95         if(vparams_button) delete vparams_button;
96 SET_TRACE
97         if(aparams_thread) delete aparams_thread;
98 SET_TRACE
99         if(vparams_thread) delete vparams_thread;
100 SET_TRACE
101 }
102
103 void FormatTools::create_objects(
104                 int &init_x, int &init_y,
105                 int do_audio, int do_video,   // Include support for audio, video
106                 int prompt_audio, int prompt_video, // Include checkbox for audio, video
107                 int prompt_audio_channels,
108                 int prompt_video_compression,
109                 const char *locked_compressor,
110                 int recording,
111                 int *file_per_label,
112                 int brender,
113                 int horizontal_layout)
114 {
115         int ys10 = yS(10);
116         int x = init_x;
117         int y = init_y;
118         int ylev = init_y;
119         int margin = mwindow->theme->widget_border;
120
121         this->locked_compressor = locked_compressor;
122         this->recording = recording;
123         this->use_brender = brender;
124         this->do_audio = do_audio;
125         this->do_video = do_video;
126         this->prompt_audio = prompt_audio;
127         this->prompt_audio_channels = prompt_audio_channels;
128         this->prompt_video = prompt_video;
129         this->prompt_video_compression = prompt_video_compression;
130         this->file_per_label = file_per_label;
131
132
133         if(asset->format == FILE_UNKNOWN)
134                 asset->format = FILE_FFMPEG;
135 //printf("FormatTools::create_objects 1\n");
136
137         if(!recording)
138         {
139                 int px = x;
140                 window->add_subwindow(path_textbox = new FormatPathText(px, y, this));
141                 path_textbox->context_help_set_keyword("File Format section");
142                 px += path_textbox->get_w() + 5;
143                 path_recent = new BC_RecentList("PATH", mwindow->defaults,
144                                         path_textbox, 10, px, y, xS(300), yS(100));
145                 window->add_subwindow(path_recent);
146                 path_recent->load_items(File::formattostr(asset->format));
147                 path_recent->context_help_set_keyword("File Format section");
148                 px += path_recent->get_w();
149                 window->add_subwindow(path_button = new BrowseButton(
150                         mwindow->theme, window, path_textbox, px, y, asset->path,
151                         _("Output to file"), _("Select a file to write to:"), 0));
152                 path_button->context_help_set_keyword("File Format section");
153
154 // Set w for user.
155                 w = MAX(w, xS(305));
156                 y += path_textbox->get_h() + ys10;
157         }
158         else
159         {
160 //              w = x + xS(305);
161                 w = xS(305);
162         }
163
164         x = init_x;
165         window->add_subwindow(format_title = new BC_Title(x, y, _("File Format:")));
166         format_title->context_help_set_keyword("File Format section");
167         x += format_title->get_w() + margin;
168         window->add_subwindow(format_text = new BC_TextBox(x, y, xS(160), 1,
169                 File::formattostr(asset->format)));
170         format_text->context_help_set_keyword("File Format section");
171         x += format_text->get_w() + margin;
172 //printf("FormatTools::create_objects %d %p\n", __LINE__, window);
173         window->add_subwindow(format_button = new FormatFormat(x, y, this));
174         format_button->create_objects();
175         format_button->context_help_set_keyword("File Format section");
176         x += format_button->get_w() + 5;
177         window->add_subwindow(ffmpeg_type = new FFMpegType(x, y, xS(70), 1, asset->fformat));
178         FFMPEG::set_asset_format(asset, mwindow->edl, asset->fformat);
179         ffmpeg_type->context_help_set_keyword("File Format section");
180         x += ffmpeg_type->get_w();
181         window->add_subwindow(format_ffmpeg = new FormatFFMPEG(x, y, this));
182         format_ffmpeg->create_objects();
183         format_ffmpeg->context_help_set_keyword("File Format section");
184         x = init_x;
185         y += format_button->get_h() + ys10;
186         if( do_audio ) {
187                 window->add_subwindow(audio_title = new BC_Title(x, y, _("Audio:"), LARGEFONT,
188                         BC_WindowBase::get_resources()->audiovideo_color));
189                 audio_title->context_help_set_keyword("File Format section");
190                 x += audio_title->get_w() + margin;
191                 window->add_subwindow(aparams_button = new FormatAParams(mwindow, this, x, y));
192                 aparams_button->context_help_set_keyword("File Format section");
193                 x += aparams_button->get_w() + margin;
194                 if(prompt_audio) {
195                         window->add_subwindow(audio_switch = new FormatAudio(x, y, this, asset->audio_data));
196                         audio_switch->context_help_set_keyword("File Format section");
197                 }
198                 x = init_x;
199                 ylev = y;
200                 y += aparams_button->get_h() + ys10;
201
202 //printf("FormatTools::create_objects 6\n");
203                 aparams_thread = new FormatAThread(this);
204         }
205
206 //printf("FormatTools::create_objects 7\n");
207         if( do_video ) {
208                 if( horizontal_layout && do_audio ) {
209                         x += xS(370);
210                         y = ylev;
211                 }
212
213 //printf("FormatTools::create_objects 8\n");
214                 window->add_subwindow(video_title = new BC_Title(x, y, _("Video:"), LARGEFONT,
215                         BC_WindowBase::get_resources()->audiovideo_color));
216                 video_title->context_help_set_keyword("File Format section");
217                 x += video_title->get_w() + margin;
218                 if(prompt_video_compression) {
219                         window->add_subwindow(vparams_button = new FormatVParams(mwindow, this, x, y));
220                         vparams_button->context_help_set_keyword("File Format section");
221                         x += vparams_button->get_w() + margin;
222                 }
223
224 //printf("FormatTools::create_objects 9\n");
225                 if(prompt_video) {
226                         window->add_subwindow(video_switch = new FormatVideo(x, y, this, asset->video_data));
227                         video_switch->context_help_set_keyword("File Format section");
228                         y += video_switch->get_h();
229                 }
230                 else {
231                         y += vparams_button->get_h();
232                 }
233
234 //printf("FormatTools::create_objects 10\n");
235                 y += ys10;
236                 vparams_thread = new FormatVThread(this);
237         }
238
239 //printf("FormatTools::create_objects 11\n");
240
241         x = init_x;
242         if( file_per_label ) {
243                 labeled_files = new FormatFilePerLabel(this, x, y, file_per_label);
244                 window->add_subwindow(labeled_files);
245                 labeled_files->context_help_set_keyword("File Format section");
246                 y += labeled_files->get_h() + ys10;
247         }
248
249 //printf("FormatTools::create_objects 12\n");
250
251         init_y = y;
252         update_format();
253 }
254
255 void FormatTools::update_driver(int driver)
256 {
257         this->video_driver = driver;
258
259         locked_compressor = 0;
260         switch(driver)
261         {
262                 case CAPTURE_DVB:
263                 case VIDEO4LINUX2MPEG:
264 // Just give the user information about how the stream is going to be
265 // stored but don't change the asset.
266 // Want to be able to revert to user settings.
267                         if(asset->format == FILE_MPEG) break;
268                         asset->format = FILE_MPEG;
269                         format_text->update(File::formattostr(asset->format));
270                         asset->audio_data = 1;
271                         asset->video_data = 1;
272                         audio_switch->update(1);
273                         video_switch->update(1);
274                         break;
275
276                 case CAPTURE_IEC61883:
277                 case CAPTURE_FIREWIRE:
278                 case VIDEO4LINUX2JPEG:
279                 case CAPTURE_JPEG_WEBCAM:
280                         asset->format = FILE_FFMPEG;
281                         format_text->update(File::formattostr(asset->format));
282
283                         switch(driver) {
284 #ifdef HAVE_DV
285                         case CAPTURE_IEC61883:
286                         case CAPTURE_FIREWIRE:
287                                 locked_compressor = (char*)CODEC_TAG_DVSD;
288                                 break;
289 #endif
290                         case VIDEO4LINUX2JPEG:
291                                 locked_compressor = (char*)CODEC_TAG_MJPEG;
292                                 break;
293
294                         case CAPTURE_JPEG_WEBCAM:
295                                 locked_compressor = (char*)CODEC_TAG_JPEG;
296                                 break;
297                         }
298                         if( locked_compressor )
299                                 strcpy(asset->vcodec, locked_compressor);
300
301                         audio_switch->update(asset->audio_data);
302                         video_switch->update(asset->video_data);
303                         break;
304
305                 default:
306                         format_text->update(File::formattostr(asset->format));
307                         audio_switch->update(asset->audio_data);
308                         video_switch->update(asset->video_data);
309                         break;
310         }
311         close_format_windows();
312         update_format();
313 }
314
315 void FormatTools::update_format()
316 {
317         if( do_audio && prompt_audio && audio_switch ) {
318                 audio_switch->update(asset->audio_data);
319                 if( File::renders_audio(asset) )
320                         audio_switch->enable();
321                 else
322                         audio_switch->disable();
323         }
324         if( do_video && prompt_video && video_switch ) {
325                 video_switch->update(asset->video_data);
326                 if( File::renders_video(asset) )
327                         video_switch->enable();
328                 else
329                         video_switch->disable();
330         }
331         if( asset->format == FILE_FFMPEG ) {
332                 ffmpeg_type->show();
333                 format_ffmpeg->show();
334         }
335         else {
336                 ffmpeg_type->hide();
337                 format_ffmpeg->hide();
338         }
339 }
340
341 int FormatTools::handle_event()
342 {
343         return 0;
344 }
345
346 Asset* FormatTools::get_asset()
347 {
348         return asset;
349 }
350
351 void FormatTools::update_extension()
352 {
353         const char *extension = File::get_tag(asset->format);
354 // split multiple extensions
355         ArrayList<const char*> extensions;
356         int len = !extension ? -1 : strlen(extension);
357         const char *extension_ptr = extension;
358         for(int i = 0; i <= len; i++)
359         {
360                 if(extension[i] == '/' || extension[i] == 0)
361                 {
362                         extensions.append(extension_ptr);
363                         extension_ptr = extension + i + 1;
364                 }
365         }
366
367         if(extensions.size())
368         {
369                 char *ptr = strrchr(asset->path, '.');
370                 if(!ptr)
371                 {
372                         ptr = asset->path + strlen(asset->path);
373                         *ptr = '.';
374                 }
375                 ptr++;
376
377 // test for equivalent extension
378                 int need_extension = 1;
379                 //int extension_len = 0;
380                 for(int i = 0; i < extensions.size() && need_extension; i++)
381                 {
382                         char *ptr1 = ptr;
383                         extension_ptr = extensions.get(i);
384 // test an extension
385                         need_extension = 0;
386                         while(*ptr1 != 0 && *extension_ptr != 0 && *extension_ptr != '/')
387                         {
388                                 if(tolower(*ptr1) != tolower(*extension_ptr))
389                                 {
390                                         need_extension = 1;
391                                         break;
392                                 }
393                                 ptr1++;
394                                 extension_ptr++;
395                         }
396
397                         if( (!*ptr1 && (*extension_ptr && *extension_ptr != '/')) ||
398                             (*ptr1 && (!*extension_ptr || *extension_ptr == '/')) )
399                                 need_extension = 1;
400                 }
401
402 //printf("FormatTools::update_extension %d %d\n", __LINE__, need_extension);
403 // copy extension
404                 if(need_extension)
405                 {
406                         char *ptr1 = ptr;
407 // change "qt" to "mov" since ffmpeg does not know qt
408                         extension_ptr = asset->format != FILE_FFMPEG ? extensions.get(0) :
409                                 !strcmp(asset->fformat, "qt" ) ||
410                                 !strcmp(asset->fformat, "pro" ) ? "mov" : asset->fformat ;
411                         while(*extension_ptr != 0 && *extension_ptr != '/')
412                                 *ptr1++ = *extension_ptr++;
413                         *ptr1 = 0;
414                 }
415
416                 int character1 = ptr - asset->path;
417                 int character2 = strlen(asset->path);
418 //              *(asset->path + character2) = 0;
419                 if(path_textbox)
420                 {
421                         path_textbox->update(asset->path);
422                         path_textbox->set_selection(character1, character2, character2);
423                 }
424         }
425 }
426
427 void FormatTools::update(Asset *asset, int *file_per_label)
428 {
429         this->asset = asset;
430         this->file_per_label = file_per_label;
431         if( file_per_label ) labeled_files->update(file_per_label);
432         if( path_textbox ) path_textbox->update(asset->path);
433         format_text->update(File::formattostr(asset->format));
434         update_format();
435         close_format_windows();
436 }
437
438 void FormatTools::close_format_windows()
439 {
440 // This is done in ~file
441         if( aparams_thread ) {
442                 if( aparams_thread->running() )
443                         aparams_thread->file->close_window();
444                 aparams_thread->join();
445         }
446         if( vparams_thread ) {
447                 if( vparams_thread->running() )
448                         vparams_thread->file->close_window();
449                 vparams_thread->join();
450         }
451 }
452
453 int FormatTools::get_w()
454 {
455         return asset->format != FILE_FFMPEG ? w :
456                 format_ffmpeg->get_x() + format_ffmpeg->get_w();
457 }
458
459 void FormatTools::set_w(int w)
460 {
461         this->w = w;
462 }
463
464 void FormatTools::reposition_window(int &init_x, int &init_y)
465 {
466         int xs10 = xS(10), xs80 = xS(80);
467         int ys10 = yS(10);
468         int x = init_x;
469         int y = init_y;
470
471         if(path_textbox)
472         {
473                 int px = x;
474                 path_textbox->reposition_window(px, y);
475                 px += path_textbox->get_w() + xS(5);
476                 path_recent->reposition_window(px, y);
477                 px += path_recent->get_w() + xS(8);
478                 path_button->reposition_window(px, y);
479                 y += path_textbox->get_h() + ys10;
480         }
481
482         format_title->reposition_window(x, y);
483         x += xS(90);
484         format_text->reposition_window(x, y);
485         x += format_text->get_w();
486         format_button->reposition_window(x, y);
487         x += format_button->get_w() + 5;
488         ffmpeg_type->reposition_window(x, y);
489         x += ffmpeg_type->get_w();
490         format_ffmpeg->reposition_window(x, y);
491
492         x = init_x;
493         y += format_button->get_h() + ys10;
494
495         if(do_audio)
496         {
497                 audio_title->reposition_window(x, y);
498                 x += xs80;
499                 aparams_button->reposition_window(x, y);
500                 x += aparams_button->get_w() + xs10;
501                 if(prompt_audio) audio_switch->reposition_window(x, y);
502
503                 x = init_x;
504                 y += aparams_button->get_h() + ys10;
505         }
506
507
508         if(do_video)
509         {
510                 video_title->reposition_window(x, y);
511                 x += xs80;
512                 if(prompt_video_compression)
513                 {
514                         vparams_button->reposition_window(x, y);
515                         x += vparams_button->get_w() + xs10;
516                 }
517
518                 if(prompt_video)
519                 {
520                         video_switch->reposition_window(x, y);
521                         y += video_switch->get_h();
522                 }
523                 else
524                 {
525                         y += vparams_button->get_h();
526                 }
527
528                 y += ys10;
529                 x = init_x;
530         }
531
532         if( file_per_label ) {
533                 labeled_files->reposition_window(x, y);
534                 y += labeled_files->get_h() + ys10;
535         }
536
537         init_y = y;
538 }
539
540
541 int FormatTools::set_audio_options()
542 {
543 //      if(video_driver == CAPTURE_DVB)
544 //      {
545 //              return 0;
546 //      }
547
548         if(!aparams_thread->running())
549         {
550                 aparams_thread->start();
551         }
552         else
553         {
554                 aparams_thread->file->raise_window();
555         }
556         return 0;
557 }
558
559 int FormatTools::set_video_options()
560 {
561 //      if(video_driver == CAPTURE_DVB)
562 //      {
563 //              return 0;
564 //      }
565
566         if(!vparams_thread->running())
567         {
568                 vparams_thread->start();
569         }
570         else
571         {
572                 vparams_thread->file->raise_window();
573         }
574
575         return 0;
576 }
577
578
579
580
581
582 FormatAParams::FormatAParams(MWindow *mwindow, FormatTools *format, int x, int y)
583  : BC_Button(x, y, mwindow->theme->get_image_set("wrench"))
584 {
585         this->format = format;
586         set_tooltip(_("Configure audio compression"));
587 }
588
589 FormatAParams::~FormatAParams()
590 {
591 }
592
593 int FormatAParams::handle_event()
594 {
595         format->set_audio_options();
596         format->handle_event();
597         return 1;
598 }
599
600
601
602
603
604 FormatVParams::FormatVParams(MWindow *mwindow, FormatTools *format, int x, int y)
605  : BC_Button(x, y, mwindow->theme->get_image_set("wrench"))
606 {
607         this->format = format;
608         set_tooltip(_("Configure video compression"));
609 }
610
611 FormatVParams::~FormatVParams()
612 {
613 }
614
615 int FormatVParams::handle_event()
616 {
617         format->set_video_options();
618         format->handle_event();
619         return 1;
620 }
621
622
623
624
625
626 FormatAThread::FormatAThread(FormatTools *format)
627  : Thread(1, 0, 0)
628 {
629         this->format = format;
630         file = new File;
631         joined = 1;
632 }
633
634 FormatAThread::~FormatAThread()
635 {
636         delete file;  file = 0;
637         join();
638 }
639
640 void FormatAThread::start()
641 {
642         join();
643         joined = 0;
644         Thread::start();
645 }
646
647
648 void FormatAThread::run()
649 {
650         file->get_options(format, 1, 0);
651 }
652
653
654
655
656 FormatVThread::FormatVThread(FormatTools *format)
657  : Thread(1, 0, 0)
658 {
659         this->format = format;
660         file = new File;
661         joined = 1;
662 }
663
664 FormatVThread::~FormatVThread()
665 {
666         delete file;  file = 0;
667         join();
668 }
669
670 void FormatVThread::start()
671 {
672         join();
673         joined = 0;
674         Thread::start();
675 }
676
677 void FormatVThread::run()
678 {
679         file->get_options(format, 0, 1);
680 }
681
682
683
684
685
686 FormatPathText::FormatPathText(int x, int y, FormatTools *format)
687  : BC_TextBox(x, y, format->w - x -
688                 2*format->mwindow->theme->get_image_set("wrench")[0]->get_w() - xS(20), 1,
689         format->asset->path)
690 {
691         this->format = format;
692 }
693
694 FormatPathText::~FormatPathText()
695 {
696 }
697 int FormatPathText::handle_event()
698 {
699         calculate_suggestions();
700         strcpy(format->asset->path, get_text());
701         format->handle_event();
702         return 1;
703 }
704
705
706
707
708 FormatAudio::FormatAudio(int x, int y, FormatTools *format, int default_)
709  : BC_CheckBox(x,
710         y,
711         default_,
712         (char*)(format->recording ? _("Record audio tracks") : _("Render audio tracks")))
713 {
714         this->format = format;
715 }
716
717 FormatAudio::~FormatAudio() {}
718 int FormatAudio::handle_event()
719 {
720         format->asset->audio_data = get_value();
721         format->handle_event();
722         return 1;
723 }
724
725
726 FormatVideo::FormatVideo(int x, int y, FormatTools *format, int default_)
727  : BC_CheckBox(x,
728         y,
729         default_,
730         (char*)(format->recording ? _("Record video tracks") : _("Render video tracks")))
731 {
732 this->format = format;
733 }
734
735 FormatVideo::~FormatVideo() {}
736 int FormatVideo::handle_event()
737 {
738         format->asset->video_data = get_value();
739         format->handle_event();
740         return 1;
741 }
742
743
744
745
746 FormatFormat::FormatFormat(int x, int y, FormatTools *format)
747  : FormatPopup(x, y, format->do_audio, format->do_video, format->use_brender)
748 {
749         this->format = format;
750 }
751
752 FormatFormat::~FormatFormat()
753 {
754 }
755
756 int FormatFormat::handle_event()
757 {
758         BC_ListBoxItem *selection = get_selection(0, 0);
759         if( selection ) {
760                 int new_format = File::strtoformat(get_selection(0, 0)->get_text());
761 //              if(new_format != format->asset->format)
762                 {
763                         Asset *asset = format->asset;
764                         asset->format = new_format;
765                         asset->audio_data = File::renders_audio(asset);
766                         asset->video_data = File::renders_video(asset);
767                         asset->ff_audio_options[0] = 0;
768                         asset->ff_video_options[0] = 0;
769                         asset->ff_format_options[0] = 0;
770                         format->format_text->update(selection->get_text());
771                         if( !format->use_brender )
772                                 format->update_extension();
773                         format->close_format_windows();
774                         if (format->path_recent) format->path_recent->
775                                 load_items(File::formattostr(format->asset->format));
776                         format->update_format();
777                 }
778                 format->handle_event();
779         }
780         return 1;
781 }
782
783
784 FormatFFMPEG::FormatFFMPEG(int x, int y, FormatTools *format)
785  : FFMPEGPopup(x, y)
786 {
787         this->format = format;
788 }
789
790 FormatFFMPEG::~FormatFFMPEG()
791 {
792 }
793
794 int FormatFFMPEG::handle_event()
795 {
796         BC_ListBoxItem *selection = get_selection(0, 0);
797         if( selection ) {
798                 const char *text = get_selection(0, 0)->get_text();
799                 format->ffmpeg_type->update(text);
800 // forces options load defaults
801                 format->asset->ff_audio_options[0] = 0;
802                 format->asset->ff_video_options[0] = 0;
803                 format->asset->ff_format_options[0] = 0;
804                 FFMPEG::set_asset_format(format->asset, format->mwindow->edl, text);
805                 format->update_extension();
806                 format->close_format_windows();
807                 format->update_format();
808                 format->handle_event();
809         }
810         return 1;
811 }
812
813
814 FormatFilePerLabel::FormatFilePerLabel(FormatTools *format,
815         int x, int y, int *output)
816  : BC_CheckBox(x, y, *output, _("Create new file at each label"))
817 {
818         this->format = format;
819         this->output = output;
820 }
821
822 FormatFilePerLabel::~FormatFilePerLabel()
823 {
824 }
825
826 int FormatFilePerLabel::handle_event()
827 {
828         *output = get_value();
829         format->handle_event();
830         return 1;
831 }
832
833 void FormatFilePerLabel::update(int *output)
834 {
835         this->output = output;
836         set_value(*output ? 1 : 0);
837 }
838
839