no longer need ffmpeg patch0 which was for Termux
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / recordgui.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008-2017 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 "batch.h"
24 #include "bcsignals.h"
25 #include "browsebutton.h"
26 #include "channel.h"
27 #include "channelpicker.h"
28 #include "clip.h"
29 #include "condition.h"
30 #include "bchash.h"
31 #include "edl.h"
32 #include "edlsession.h"
33 #include "file.h"
34 #include "filesystem.h"
35 #include "keys.h"
36 #include "language.h"
37 #include "loadmode.h"
38 #include "meterpanel.h"
39 #include "mutex.h"
40 #include "mwindow.h"
41 #include "mwindowgui.h"
42 #include "preferences.h"
43 #include "question.h"
44 #include "recconfirmdelete.h"
45 #include "recordgui.h"
46 #include "record.h"
47 #include "recordlabel.h"
48 #include "recordmonitor.h"
49 #include "recordtransport.h"
50 #include "recordvideo.h"
51 #include "mainsession.h"
52 #include "theme.h"
53 #include "units.h"
54 #include "videodevice.h"
55
56 #include <time.h>
57
58
59
60
61 RecordGUI::RecordGUI(MWindow *mwindow, Record *record)
62  : BC_Window(_(PROGRAM_NAME ": Recording"),
63         mwindow->session->rwindow_x, mwindow->session->rwindow_y,
64         mwindow->session->rwindow_w, mwindow->session->rwindow_h,
65         xS(10), yS(10), 1, 0, 1)
66 {
67         this->mwindow = mwindow;
68         this->record = record;
69
70         current_operation = 0;
71         position_title = 0;
72         prev_label_title = 0;
73         frames_behind = 0;
74         frames_dropped = 0;
75         framerate = 0;
76         samples_clipped = 0;
77         cron_status = 0;
78         batch_bay = 0;
79         batch_path = 0;
80         status_thread = 0;
81         batch_start = 0;
82         batch_duration = 0;
83         record_transport = 0;
84         batch_browse = 0;
85         batch_source = 0;
86         batch_mode = 0;
87         new_batch = 0;
88         delete_batch = 0;
89         start_batches = 0;
90         stop_batches = 0;
91         activate_batch = 0;
92         label_button = 0;
93         drop_frames = 0;
94         fill_frames = 0;
95         monitor_video = 0;
96         monitor_audio = 0;
97         meter_audio = 0;
98         batch_flash = 0;
99         startover_thread = 0;
100         interrupt_thread = 0;
101         load_mode = 0;
102         flash_color = 0;
103         loop_hr = 0;
104         loop_min = 0;
105         loop_sec = 0;
106         reset = 0;
107         monitor_video_window = 0;
108         dc_offset_button = 0;
109         for( int i=0; i<MAXCHANNELS; ++i ) {
110                 dc_offset_text[i] = 0;
111                 meter[i] = 0;
112         }
113         total_dropped_frames = 0;
114         total_clipped_samples = 0;
115 // *** CONTEXT_HELP ***
116         context_help_set_keyword("Record Web Media");
117 }
118
119 RecordGUI::~RecordGUI()
120 {
121         delete status_thread;
122         delete record_transport;
123         delete batch_source;
124         delete batch_mode;
125         delete batch_flash;
126         delete startover_thread;
127         delete interrupt_thread;
128         delete batch_start;
129         delete batch_duration;
130         delete load_mode;
131 }
132
133
134 void RecordGUI::create_objects()
135 {
136         int xs5 = xS(5), xs10 = xS(10), xs20 = xS(20), xs30 = xS(30);
137         int ys5 = yS(5), ys10 = yS(10);
138         char string[BCTEXTLEN];
139         flash_color = RED;
140         Asset *asset = record->default_asset;
141         lock_window("RecordGUI::create_objects");
142         status_thread = new RecordStatusThread(mwindow, this);
143         status_thread->start();
144         set_icon(mwindow->theme->get_image("record_icon"));
145
146         mwindow->theme->get_recordgui_sizes(this, get_w(), get_h());
147 //printf("RecordGUI::create_objects 1\n");
148         mwindow->theme->draw_rwindow_bg(this);
149
150         int x = xs10;
151         int y = ys10;
152         int x1 = 0;
153         BC_Title *title;
154         int pad = max(BC_TextBox::calculate_h(this, MEDIUMFONT, 1, 1),
155                 BC_Title::calculate_h(this, "X")) + ys5;
156         int button_y = 0;
157
158 // Current batch
159         add_subwindow(title = new BC_Title(x, y, _("Path:")));
160         x1 = max(title->get_w(), x1);
161         y += pad;
162         add_subwindow(title = new BC_Title(x, y, _("Start time:")));
163         x1 = max(title->get_w(), x1);
164         y += pad;
165         add_subwindow(title = new BC_Title(x, y, _("Duration time:")));
166         x1 = max(title->get_w(), x1);
167         y += pad;
168         add_subwindow(title = new BC_Title(x, y, _("Source:")));
169         x1 = max(title->get_w(), x1);
170         y += pad;
171         add_subwindow(title = new BC_Title(x, y, _("Mode:")));
172         x1 = max(title->get_w(), x1);
173         y += pad;
174         add_subwindow(title = new BC_Title(x, y, _("Transport:")));
175         x1 = max(title->get_w(), x1);
176         y += pad;
177
178         button_y = max(y, button_y);
179
180
181
182         int x2 = 0;
183         y = ys10;
184         x = x1 + xs20;
185         add_subwindow(batch_path = new RecordPath(this, x, y));
186         add_subwindow(batch_browse = new BrowseButton(mwindow->theme,
187                 this,
188                 batch_path,
189                 batch_path->get_x() + batch_path->get_w(),
190                 y,
191                 asset->path,
192                 _(PROGRAM_NAME ": Record path"),
193                 _("Select a file to record to:"),
194                 0));
195         x2 = max(x2, batch_path->get_w() + batch_browse->get_w());
196         y += pad;
197         batch_start = new RecordStart(this, x, y);
198         batch_start->create_objects();
199         x2 = max(x2, batch_start->get_w());
200         y += pad;
201         batch_duration = new RecordDuration(this, x, y);
202         batch_duration->create_objects();
203         x2 = max(x2, batch_duration->get_w());
204         y += pad;
205         batch_source = new RecordSource(this, x, y);
206         batch_source->create_objects();
207         x2 = max(x2, batch_source->get_w());
208         y += pad;
209         batch_mode = new RecordGUIModeMenu(this, x, y, xS(200), "");
210         batch_mode->create_objects();
211         x2 = max(x2, batch_mode->get_w());
212         y += pad;
213         record_transport = new RecordTransport(mwindow,
214                 record, this, x, y);
215         record_transport->create_objects();
216         x2 = max(x2, record_transport->get_w());
217
218
219
220
221 // Compression settings
222         x = x2 + x1 + xs30;
223         y = ys10;
224         int x3 = 0;
225         pad = BC_Title::calculate_h(this, "X") + ys5;
226         add_subwindow(title = new BC_Title(x, y, _("Format:")));
227         x3 = max(title->get_w(), x3);
228         y += pad;
229
230         if(asset->audio_data)
231         {
232                 add_subwindow(title = new BC_Title(x, y, _("Audio compression:")));
233                 x3 = max(title->get_w(), x3);
234                 y += pad;
235                 add_subwindow(title = new BC_Title(x, y, _("Samplerate:")));
236                 x3 = max(title->get_w(), x3);
237                 y += pad;
238                 add_subwindow(title = new BC_Title(x, y, _("Clipped samples:")));
239                 x3 = max(title->get_w(), x3);
240                 y += pad;
241         }
242
243         if(asset->video_data)
244         {
245                 add_subwindow(title = new BC_Title(x, y, _("Video compression:")));
246                 x3 = max(title->get_w(), x3);
247                 y += pad;
248                 add_subwindow(title = new BC_Title(x, y, _("Framerate:")));
249                 x3 = max(title->get_w(), x3);
250                 y += pad;
251                 add_subwindow(title = new BC_Title(x, y, _("Frames dropped:")));
252                 x3 = max(title->get_w(), x3);
253                 y += pad;
254                 add_subwindow(title = new BC_Title(x, y, _("Frames behind:")));
255                 x3 = max(title->get_w(), x3);
256                 y += pad;
257         }
258
259         add_subwindow(title = new BC_Title(x, y, _("Position:")));
260         x3 = max(title->get_w(), x3);
261         y += pad;
262         add_subwindow(title = new BC_Title(x, y, _("Prev label:")));
263         x3 = max(title->get_w(), x3);
264         y += pad;
265
266         button_y = max(y, button_y);
267         y = ys10;
268         x = x3 + x2 + x1 + xS(40);
269
270         add_subwindow(new BC_Title(x, y,
271                 File::formattostr(asset->format),
272                 MEDIUMFONT,
273                 mwindow->theme->recordgui_fixed_color));
274         y += pad;
275
276         if(asset->audio_data) {
277                 add_subwindow(new BC_Title(x, y,
278                         File::bitstostr(asset->bits),
279                         MEDIUMFONT,
280                         mwindow->theme->recordgui_fixed_color));
281
282                 y += pad;
283                 sprintf(string, "%d", asset->sample_rate);
284                 add_subwindow(new BC_Title(x, y,
285                         string, MEDIUMFONT,
286                         mwindow->theme->recordgui_fixed_color));
287
288                 y += pad;
289                 add_subwindow(samples_clipped = new BC_Title(x, y,
290                         "0", MEDIUMFONT,
291                         mwindow->theme->recordgui_variable_color));
292                 y += pad;
293         }
294
295         if(asset->video_data) {
296                 add_subwindow(new BC_Title(x, y,
297                         asset->format == FILE_MPEG ? _("File Capture") :
298                                 File::compressiontostr(asset->vcodec),
299                         MEDIUMFONT,
300                         mwindow->theme->recordgui_fixed_color));
301
302                 y += pad;
303                 sprintf(string, "%0.2f", asset->frame_rate);
304                 add_subwindow(framerate = new BC_Title(x, y,
305                         string, MEDIUMFONT,
306                         mwindow->theme->recordgui_fixed_color));
307
308                 y += pad;
309                 add_subwindow(frames_dropped = new BC_Title(x, y,
310                         "0", MEDIUMFONT,
311                         mwindow->theme->recordgui_variable_color));
312                 y += pad;
313                 add_subwindow(frames_behind = new BC_Title(x, y,
314                         "0", MEDIUMFONT,
315                         mwindow->theme->recordgui_variable_color));
316                 y += pad;
317         }
318
319         add_subwindow(position_title = new BC_Title(x, y,
320                 "", MEDIUMFONT,
321                 mwindow->theme->recordgui_variable_color));
322
323         y += pad;
324         add_subwindow(prev_label_title = new BC_Title(x, y,
325                 _("None"), MEDIUMFONT,
326                 mwindow->theme->recordgui_variable_color));
327
328         y += pad + ys10;
329         button_y = max(y, button_y);
330
331 // Buttons
332         x = xs10;
333         y = button_y;
334
335         add_subwindow(title = new BC_Title(x,y, _("Batches:")));
336         int y_max = y + title->get_h();  x1 = x;
337         x += title->get_w() + xs5;
338         add_subwindow(activate_batch = new RecordGUIActivateBatch(this, x, y));
339         x += activate_batch->get_w();
340         y_max = max(y_max, y + activate_batch->get_h());
341         add_subwindow(start_batches = new RecordGUIStartBatches(this, x, y));
342         y_max = max(y_max, y + start_batches->get_h());  x2 = x;
343         x += start_batches->get_w();
344         add_subwindow(new_batch = new RecordGUINewBatch(this, x, y));
345         y_max = max(y_max, y + new_batch->get_h());  x3 = x;
346         x += new_batch->get_w();  int x4 = x;
347         add_subwindow(label_button = new RecordGUILabel(this, x, y));
348         y_max = max(y_max, y + label_button->get_h());
349
350         int y1 = y_max, y2 = y1 + ys5;
351         add_subwindow(title = new BC_Title(x1,y2, _("Cron:")));
352         y_max = max(y_max, y2 + title->get_h());
353         x1 += title->get_w() + xs5;
354         add_subwindow(cron_status = new BC_Title(x1,y2, _("Idle"), MEDIUMFONT,
355                 mwindow->theme->recordgui_variable_color));
356         y_max = max(y_max, y2 + cron_status->get_h());
357         add_subwindow(stop_batches = new RecordGUIStopBatches(this, x2, y1));
358         y_max = max(y_max, y1 + stop_batches->get_h());
359         add_subwindow(delete_batch = new RecordGUIDeleteBatch(this, x3, y1));
360         y_max = max(y_max, y1 + delete_batch->get_h());
361         add_subwindow(clrlbls_button = new RecordGUIClearLabels(this, x4, y1));
362         y_max = max(y_max, y1 + clrlbls_button->get_h());
363
364         x = x1 = xs10;
365         y = y_max + pad;
366         y1 = y + pad + ys5;
367
368         fill_frames = 0;
369         monitor_video = 0;
370         monitor_audio = 0;
371         meter_audio = 0;
372         if(asset->video_data) {
373                 add_subwindow(drop_frames = new RecordGUIDropFrames(this, x, y));
374                 add_subwindow(fill_frames = new RecordGUIFillFrames(this, x, y1));
375                 x += drop_frames->get_w() + xs5;  x1 = x;
376                 add_subwindow(monitor_video = new RecordGUIMonitorVideo(this, x, y));
377                 x += monitor_video->get_w() + xs5;
378         }
379
380         if(asset->audio_data) {
381                 add_subwindow(monitor_audio = new RecordGUIMonitorAudio(this, x, y));
382                 x += monitor_audio->get_w() + xs5;
383                 add_subwindow(meter_audio = new RecordGUIAudioMeters(this, x, y));
384                 x += meter_audio->get_w() + xs5;
385         }
386
387         add_subwindow(power_off = new RecordGUIPowerOff(this, x1, y1));
388         x1 += power_off->get_w() + xs10;
389         add_subwindow(commercial_check = new RecordGUICommCheck(this, x1, y1));
390         x1 += commercial_check->get_w() + xs30;
391         add_subwindow(deinterlace = new RecordGUIDeinterlace(this, x1, y1));
392         deinterlace->create_objects();
393         x1 += deinterlace->get_w() + xs5;
394         add_subwindow(new BC_Title(x1, y1, _("deinterlace")));
395
396 // Batches
397         x = xs10;
398         y += ys5;
399         if( fill_frames )
400                 y = y1 + fill_frames->get_h();
401         else if( monitor_audio )
402                 y += monitor_audio->get_h();
403
404         int bottom_margin = max(BC_OKButton::calculate_h(),
405                 LoadMode::calculate_h(this, mwindow->theme)) + ys5;
406
407
408         add_subwindow(batch_bay = new RecordGUIBatches(this, x, y,
409                 get_w() - xs20, get_h() - y - bottom_margin - ys10));
410         y += batch_bay->get_h() + ys5;
411         record->record_batches.gui = batch_bay;
412         batch_bay->update_batches(-1);
413
414 // Controls
415         int loadmode_w = LoadMode::calculate_w(this, mwindow->theme);
416         load_mode = new LoadMode(mwindow, this,
417                 get_w() / 2 - loadmode_w / 2, y, &record->load_mode);
418         load_mode->create_objects();
419         y += load_mode->get_h() + ys5;
420
421         add_subwindow(new RecordGUIOK(this));
422
423         interrupt_thread = new EndRecordThread(this);
424 //      add_subwindow(new RecordGUISave(record, this));
425         add_subwindow(new RecordGUICancel(this));
426
427         startover_thread = new RecordStartoverThread(this);
428
429         enable_batch_buttons();
430         if( batch_mode->value == RECORD_TIMED )
431                 batch_duration->enable();
432         else
433                 batch_duration->disable();
434         show_window(1);
435         unlock_window();
436 }
437
438 void RecordGUI::update_batches()
439 {
440         lock_window("void RecordGUI::Update_batches");
441         batch_bay->update_batches();
442         unlock_window();
443 }
444
445
446 Batch *RecordGUI::get_current_batch()
447 {
448         return record->get_editing_batch();
449 }
450
451 Batch *RecordGUI::get_editing_batch()
452 {
453         return record->get_editing_batch();
454 }
455
456 void RecordGUI::update_batch_sources()
457 {
458 //printf("RecordGUI::update_batch_sources 1\n");
459         ChannelPicker *channel_picker =
460                 record->record_monitor->window->channel_picker;
461         if(channel_picker)
462                 batch_source->update_list(&channel_picker->channel_listitems);
463 //printf("RecordGUI::update_batch_sources 2\n");
464 }
465
466 int RecordGUI::translation_event()
467 {
468         mwindow->session->rwindow_x = get_x();
469         mwindow->session->rwindow_y = get_y();
470         return 0;
471 }
472
473
474 int RecordGUI::resize_event(int w, int h)
475 {
476         int xs20 = xS(20), ys10 = yS(10);
477 // Recompute batch list based on previous extents
478         int bottom_margin = mwindow->session->rwindow_h -
479                 batch_bay->get_y() -
480                 batch_bay->get_h();
481         int mode_margin = mwindow->session->rwindow_h - load_mode->get_y();
482         mwindow->session->rwindow_x = get_x();
483         mwindow->session->rwindow_y = get_y();
484         mwindow->session->rwindow_w = w;
485         mwindow->session->rwindow_h = h;
486         mwindow->theme->get_recordgui_sizes(this, w, h);
487         mwindow->theme->draw_rwindow_bg(this);
488
489         int new_h = mwindow->session->rwindow_h - bottom_margin - batch_bay->get_y();
490         if(new_h < ys10) new_h = ys10;
491         batch_bay->reposition_window(batch_bay->get_x(),
492                 batch_bay->get_y(),
493                 mwindow->session->rwindow_w - xs20,
494                 mwindow->session->rwindow_h - bottom_margin - batch_bay->get_y());
495
496         load_mode->reposition_window(mwindow->session->rwindow_w / 2 -
497                         mwindow->theme->loadmode_w / 2,
498                 mwindow->session->rwindow_h - mode_margin);
499
500         flash();
501         return 1;
502 }
503
504 void RecordGUI::update_batch_tools()
505 {
506         lock_window("RecordGUI::update_batch_tools");
507 //printf("RecordGUI::update_batch_tools 1\n");
508         Batch *batch = get_editing_batch();
509         batch_path->update(batch->asset->path);
510
511 // File is open in editing batch
512 //      if(current_batch() == editing_batch() && record->file)
513 //              batch_path->disable();
514 //      else
515 //              batch_path->enable();
516
517         batch_start->update(&batch->start_day, &batch->start_time);
518         batch_duration->update(0, &batch->duration);
519         batch_source->update(batch->get_source_text());
520         batch_mode->update(batch->record_mode);
521         if( batch_mode->value == RECORD_TIMED )
522                 batch_duration->enable();
523         else
524                 batch_duration->disable();
525         flush();
526         unlock_window();
527 }
528
529 void RecordGUI::enable_batch_buttons()
530 {
531         lock_window("RecordGUI::enable_batch_buttons");
532         new_batch->enable();
533         delete_batch->enable();
534         start_batches->enable();
535         stop_batches->disable();
536         activate_batch->enable();
537         unlock_window();
538 }
539
540 void RecordGUI::disable_batch_buttons()
541 {
542         lock_window("RecordGUI::disable_batch_buttons");
543         new_batch->disable();
544         delete_batch->disable();
545         start_batches->disable();
546         stop_batches->enable();
547         activate_batch->disable();
548         unlock_window();
549 }
550
551 RecordGUIBatches::RecordGUIBatches(RecordGUI *gui, int x, int y, int w, int h)
552  : RecordBatchesGUI(gui->record->record_batches, x, y, w, h)
553 {
554         this->gui = gui;
555 }
556
557 // Do nothing for double clicks to protect active batch
558 int RecordGUIBatches::handle_event()
559 {
560         return 1;
561 }
562
563 int RecordGUIBatches::selection_changed()
564 {
565         RecordBatchesGUI::selection_changed();
566         gui->update_batch_tools();
567         return 1;
568 }
569
570
571 RecordGUISave::RecordGUISave(RecordGUI *gui)
572  : BC_Button(xS(10),
573         gui->get_h() - BC_WindowBase::get_resources()->ok_images[0]->get_h() - yS(10),
574         BC_WindowBase::get_resources()->ok_images)
575 {
576         set_tooltip(_("Save the recording and quit."));
577         this->gui = gui;
578 }
579
580 int RecordGUISave::handle_event()
581 {
582         gui->set_done(0);
583         return 1;
584 }
585
586 int RecordGUISave::keypress_event()
587 {
588 //      if(get_keypress() == RETURN)
589 //      {
590 //              handle_event();
591 //              return 1;
592 //      }
593         return context_help_check_and_show();
594 }
595
596 RecordGUICancel::RecordGUICancel(RecordGUI *gui)
597  : BC_CancelButton(gui)
598 {
599         set_tooltip(_("Quit without pasting into project."));
600         this->gui = gui;
601 }
602
603 int RecordGUICancel::handle_event()
604 {
605         gui->interrupt_thread->start(0);
606         return 1;
607 }
608
609 int RecordGUICancel::keypress_event()
610 {
611         if(get_keypress() == ESC)
612         {
613                 handle_event();
614                 return 1;
615         }
616
617         return context_help_check_and_show();
618 }
619
620
621 RecordGUIOK::RecordGUIOK(RecordGUI *gui)
622  : BC_OKButton(gui)
623 {
624         set_tooltip(_("Quit and paste into project."));
625         this->gui = gui;
626 }
627
628 int RecordGUIOK::handle_event()
629 {
630         gui->interrupt_thread->start(1);
631         return 1;
632 }
633
634
635 RecordGUIStartOver::RecordGUIStartOver(RecordGUI *gui, int x, int y)
636  : BC_GenericButton(x, y, _("Start Over"))
637 {
638         set_tooltip(_("Rewind the current file and erase."));
639         this->gui = gui;
640 }
641 RecordGUIStartOver::~RecordGUIStartOver()
642 {
643 }
644
645 int RecordGUIStartOver::handle_event()
646 {
647         if(!gui->startover_thread->running())
648                 gui->startover_thread->start();
649         return 1;
650 }
651
652
653 RecordGUIDropFrames::RecordGUIDropFrames(RecordGUI *gui, int x, int y)
654  : BC_CheckBox(x, y, gui->record->drop_overrun_frames, _("drop overrun frames"))
655 {
656         this->set_underline(0);
657         this->gui = gui;
658         set_tooltip(_("Drop input frames when behind."));
659 }
660
661 int RecordGUIDropFrames::handle_event()
662 {
663         gui->record->drop_overrun_frames = get_value();
664         return 1;
665 }
666
667 int RecordGUIDropFrames::keypress_event()
668 {
669         if( get_keypress() == caption[0] ) {
670                 set_value(get_value() ? 0 : 1);
671                 handle_event();
672                 return 1;
673         }
674         return context_help_check_and_show();
675 }
676
677 RecordGUIFillFrames::RecordGUIFillFrames(RecordGUI *gui, int x, int y)
678  : BC_CheckBox(x, y, gui->record->fill_underrun_frames, _("fill underrun frames"))
679 {
680         this->set_underline(0);
681         this->gui = gui;
682         set_tooltip(_("Write extra frames when behind."));
683 }
684
685 int RecordGUIFillFrames::handle_event()
686 {
687         gui->record->fill_underrun_frames = get_value();
688         return 1;
689 }
690
691 int RecordGUIFillFrames::keypress_event()
692 {
693         if( get_keypress() == caption[0] ) {
694                 set_value(get_value() ? 0 : 1);
695                 handle_event();
696                 return 1;
697         }
698         return context_help_check_and_show();
699 }
700
701 RecordGUIPowerOff::RecordGUIPowerOff(RecordGUI *gui, int x, int y)
702  : BC_CheckBox(x, y, gui->record->power_off, _("poweroff when done"))
703 {
704         this->set_underline(0);
705         this->gui = gui;
706         set_tooltip(_("poweroff system when batch record done."));
707 // *** CONTEXT_HELP ***
708         context_help_set_keyword("Capture at some Future Time via Batch");
709 }
710
711 int RecordGUIPowerOff::handle_event()
712 {
713         gui->record->power_off = get_value();
714         return 1;
715 }
716
717 int RecordGUIPowerOff::keypress_event()
718 {
719         if( get_keypress() == caption[0] ) {
720                 set_value(get_value() ? 0 : 1);
721                 handle_event();
722                 return 1;
723         }
724         return context_help_check_and_show();
725 }
726
727
728 RecordGUICommCheck::RecordGUICommCheck(RecordGUI *gui, int x, int y)
729  : BC_CheckBox(x, y, gui->record->commercial_check, _("check for ads"))
730 {
731         this->set_underline(0);
732         this->gui = gui;
733         set_tooltip(_("check for commercials."));
734 // *** CONTEXT_HELP ***
735         context_help_set_keyword("The commercial DB");
736 }
737
738 int RecordGUICommCheck::handle_event()
739 {
740         gui->record->update_skimming(get_value());
741         return 1;
742 }
743
744 int RecordGUICommCheck::keypress_event()
745 {
746         if( get_keypress() == caption[0] ) {
747                 set_value(get_value() ? 0 : 1);
748                 gui->record->update_skimming(get_value());
749                 handle_event();
750                 return 1;
751         }
752         return context_help_check_and_show();
753 }
754
755
756 RecordGUIDelaceItem::RecordGUIDelaceItem(RecordGUIDeinterlace *popup,
757                 const char *text, int id)
758  : BC_MenuItem(text)
759 {
760         this->popup = popup;
761         this->id = id;
762 }
763 int RecordGUIDelaceItem::handle_event()
764 {
765         popup->gui->record->deinterlace = id;
766         popup->update();
767         return 1;
768 }
769
770 RecordGUIDeinterlace::RecordGUIDeinterlace(RecordGUI *gui, int x, int y)
771  : BC_PopupMenu(x, y, xS(24), "", 1, 0, xS(3))
772 {
773         this->gui = gui;
774 }
775
776 void RecordGUIDeinterlace::create_objects()
777 {
778         add_item(new RecordGUIDelaceItem(this, _("None"), RECORD_LACE_NONE));
779         add_item(new RecordGUIDelaceItem(this, _("Even"), RECORD_LACE_EVEN));
780         add_item(new RecordGUIDelaceItem(this, _("Odd"), RECORD_LACE_ODD));
781         update();
782 }
783
784 void RecordGUIDeinterlace::update()
785 {
786         int v = gui->record->deinterlace;
787         for( int i=0,n=total_items(); i<n; ++i ) {
788                 RecordGUIDelaceItem *item = (RecordGUIDelaceItem *)get_item(i);
789                 item->set_checked(item->id == v);
790         }
791 }
792
793
794 RecordGUIMonitorVideo::RecordGUIMonitorVideo(RecordGUI *gui, int x, int y)
795  : BC_CheckBox(x, y, gui->record->monitor_video, _("Monitor video"))
796 {
797         this->set_underline(8);
798         this->gui = gui;
799 }
800
801 int RecordGUIMonitorVideo::handle_event()
802 {
803 // Video capture constitutively, just like audio, but only flash on screen if 1
804         int mode = get_value();
805         Record *record = gui->record;
806         record->set_video_monitoring(mode);
807         if(record->monitor_video) {
808                 unlock_window();
809                 BC_Window *window = record->record_monitor->window;
810                 window->lock_window("RecordGUIMonitorVideo::handle_event");
811                 window->show_window();
812                 window->raise_window();
813                 window->flush();
814                 window->unlock_window();
815                 lock_window("RecordGUIMonitorVideo::handle_event");
816                 record->video_window_open = 1;
817         }
818         else {
819                 unlock_window();
820                 BC_Window *window = record->record_monitor->window;
821                 window->lock_window("RecordGUIMonitorVideo::handle_event");
822                 window->hide_window();
823                 window->flush();
824                 window->unlock_window();
825                 lock_window("RecordGUIMonitorVideo::handle_event");
826                 record->video_window_open = 0;
827         }
828         return 1;
829 }
830
831
832 int RecordGUIMonitorVideo::keypress_event()
833 {
834         if(get_keypress() == 'v') {
835                 set_value(get_value() ? 0 : 1);
836                 handle_event();
837                 return 1;
838         }
839         return context_help_check_and_show();
840 }
841
842
843
844 RecordGUIMonitorAudio::RecordGUIMonitorAudio(RecordGUI *gui, int x, int y)
845  : BC_CheckBox(x, y, gui->record->monitor_audio, _("Monitor audio"))
846 {
847         this->set_underline(8);
848         this->gui = gui;
849 }
850
851 int RecordGUIMonitorAudio::handle_event()
852 {
853         int mode = get_value();
854         Record *record = gui->record;
855         record->set_audio_monitoring(mode);
856         if(record->monitor_audio) {
857                 unlock_window();
858                 BC_Window *window = record->record_monitor->window;
859                 window->lock_window("RecordGUIMonitorAudio::handle_event");
860                 window->show_window();
861                 window->raise_window();
862                 window->flush();
863                 window->unlock_window();
864                 lock_window("RecordGUIMonitorAudio::handle_event");
865                 record->video_window_open = 1;
866         }
867         return 1;
868 }
869
870 int RecordGUIMonitorAudio::keypress_event()
871 {
872         if(get_keypress() == 'a') {
873                 set_value(get_value() ? 0 : 1);
874                 handle_event();
875                 return 1;
876         }
877         return context_help_check_and_show();
878 }
879
880
881 RecordGUIAudioMeters::RecordGUIAudioMeters(RecordGUI *gui, int x, int y)
882  : BC_CheckBox(x, y, gui->record->metering_audio, _("Audio meters"))
883 {
884         this->set_underline(6);
885         this->gui = gui;
886 // *** CONTEXT_HELP ***
887         context_help_set_keyword("Sound Level Meters Window");
888 }
889
890 int RecordGUIAudioMeters::handle_event()
891 {
892         int mode = get_value();
893         Record *record = gui->record;
894         record->set_audio_metering(mode);
895         if(record->metering_audio) {
896                 unlock_window();
897                 BC_Window *window = record->record_monitor->window;
898                 window->lock_window("RecordGUIAudioMeters::handle_event");
899                 window->show_window();
900                 window->raise_window();
901                 window->flush();
902                 window->unlock_window();
903                 lock_window("RecordGUIAudioMeters::handle_event");
904                 record->video_window_open = 1;
905         }
906         return 1;
907 }
908
909 int RecordGUIAudioMeters::keypress_event()
910 {
911         if(get_keypress() == 'm') {
912                 set_value(get_value() ? 0 : 1);
913                 handle_event();
914                 return 1;
915         }
916         return context_help_check_and_show();
917 }
918
919 RecordPath::RecordPath(RecordGUI *gui, int x, int y)
920  : RecordBatchesGUI::Path(gui->record->record_batches, x, y)
921 {
922         this->gui = gui;
923 }
924
925 int RecordPath::handle_event()
926 {
927         return RecordBatchesGUI::Path::handle_event();
928 }
929
930
931 RecordStart::RecordStart(RecordGUI *gui, int x, int y)
932  : RecordBatchesGUI::StartTime(gui, gui->record->record_batches, x, y)
933 {
934         this->gui = gui;
935 }
936
937 int RecordStart::handle_event()
938 {
939         return RecordBatchesGUI::StartTime::handle_event();
940 }
941
942 RecordDuration::RecordDuration(RecordGUI *gui, int x, int y)
943  : RecordBatchesGUI::Duration(gui, gui->record->record_batches, x, y)
944 {
945         this->gui = gui;
946 }
947
948 int RecordDuration::handle_event()
949 {
950         return RecordBatchesGUI::Duration::handle_event();
951 }
952
953
954 RecordSource::RecordSource(RecordGUI *gui, int x, int y)
955  : RecordBatchesGUI::Source(gui, gui->record->record_batches, x, y)
956 {
957         this->gui = gui;
958 }
959
960 int RecordSource::handle_event()
961 {
962         gui->record->set_batch_channel_no(get_number());
963         return RecordBatchesGUI::Source::handle_event();
964 }
965
966
967 RecordNews::RecordNews(RecordGUI *gui, int x, int y)
968  : RecordBatchesGUI::News(gui->record->record_batches, x, y)
969 {
970         this->gui = gui;
971 }
972
973 int RecordNews::handle_event()
974 {
975         return RecordBatchesGUI::News::handle_event();
976 }
977
978
979 RecordGUINewBatch::RecordGUINewBatch(RecordGUI *gui, int x, int y)
980  : RecordBatchesGUI::NewBatch(gui->record->record_batches, x, y)
981 {
982         this->gui = gui;
983         set_tooltip(_("Create new clip."));
984 // *** CONTEXT_HELP ***
985         context_help_set_keyword("Capture at some Future Time via Batch");
986 }
987 int RecordGUINewBatch::handle_event()
988 {
989         gui->record->new_batch();
990         return RecordBatchesGUI::NewBatch::handle_event();
991 }
992
993
994 RecordGUIDeleteBatch::RecordGUIDeleteBatch(RecordGUI *gui, int x, int y)
995  : RecordBatchesGUI::DeleteBatch(gui->record->record_batches, x, y)
996 {
997         this->gui = gui;
998         set_tooltip(_("Delete clip."));
999 // *** CONTEXT_HELP ***
1000         context_help_set_keyword("Capture at some Future Time via Batch");
1001 }
1002
1003 int RecordGUIDeleteBatch::handle_event()
1004 {
1005         gui->record->delete_batch();
1006         return RecordBatchesGUI::DeleteBatch::handle_event();
1007 }
1008
1009
1010 RecordGUIStartBatches::RecordGUIStartBatches(RecordGUI *gui, int x, int y)
1011  : RecordBatchesGUI::StartBatches(gui->record->record_batches, x, y)
1012 {
1013         this->gui = gui;
1014         set_tooltip(_("Start batch recording\nfrom the current position."));
1015 // *** CONTEXT_HELP ***
1016         context_help_set_keyword("Capture at some Future Time via Batch");
1017 }
1018
1019 int RecordGUIStartBatches::handle_event()
1020 {
1021         Record *record = gui->record;
1022         record->start_cron_thread();
1023         return RecordBatchesGUI::StartBatches::handle_event();
1024 }
1025
1026
1027 RecordGUIStopBatches::RecordGUIStopBatches(RecordGUI *gui, int x, int y)
1028  : RecordBatchesGUI::StopBatches(gui->record->record_batches, x, y)
1029 {
1030         this->gui = gui;
1031 // *** CONTEXT_HELP ***
1032         context_help_set_keyword("Capture at some Future Time via Batch");
1033 }
1034
1035 int RecordGUIStopBatches::handle_event()
1036 {
1037         Record *record = gui->record;
1038         unlock_window();
1039         record->stop_cron_thread(_("Stopped"));
1040         lock_window();
1041         return RecordBatchesGUI::StopBatches::handle_event();
1042 }
1043
1044
1045 RecordGUIActivateBatch::RecordGUIActivateBatch(RecordGUI *gui, int x, int y)
1046  : RecordBatchesGUI::ActivateBatch(gui->record->record_batches, x, y)
1047 {
1048         this->gui = gui;
1049         set_tooltip(_("Make the highlighted\nclip active."));
1050 // *** CONTEXT_HELP ***
1051         context_help_set_keyword("Capture at some Future Time via Batch");
1052 }
1053 int RecordGUIActivateBatch::handle_event()
1054 {
1055         gui->record->activate_batch(gui->record->editing_batch());
1056         gui->update_cron_status(_("Idle"));
1057         return RecordBatchesGUI::ActivateBatch::handle_event();
1058 }
1059
1060
1061 RecordGUILabel::RecordGUILabel(RecordGUI *gui, int x, int y)
1062  : BC_GenericButton(x, y, _("Label"))
1063 {
1064         this->gui = gui;
1065         set_underline(0);
1066 // *** CONTEXT_HELP ***
1067         context_help_set_keyword("Capture at some Future Time via Batch");
1068 }
1069
1070
1071 RecordGUILabel::~RecordGUILabel()
1072 {
1073 }
1074
1075 int RecordGUILabel::handle_event()
1076 {
1077         gui->record->toggle_label();
1078         return 1;
1079 }
1080
1081 int RecordGUILabel::keypress_event()
1082 {
1083         if( get_keypress() == *get_text() ) {
1084                 handle_event();
1085                 return 1;
1086         }
1087         return context_help_check_and_show();
1088 }
1089
1090
1091 RecordGUIClearLabels::RecordGUIClearLabels(RecordGUI *gui, int x, int y)
1092  : BC_GenericButton(x, y, _("ClrLbls"))
1093 {
1094         this->gui = gui;
1095 // *** CONTEXT_HELP ***
1096         context_help_set_keyword("Capture at some Future Time via Batch");
1097 }
1098
1099
1100 RecordGUIClearLabels::~RecordGUIClearLabels()
1101 {
1102 }
1103
1104 int RecordGUIClearLabels::handle_event()
1105 {
1106         gui->record->clear_labels();
1107         return 1;
1108 }
1109
1110
1111 EndRecordThread::EndRecordThread(RecordGUI *gui)
1112  : Thread(1, 0, 0)
1113 {
1114         this->gui = gui;
1115         is_ok = 0;
1116 }
1117
1118 EndRecordThread::~EndRecordThread()
1119 {
1120         if(Thread::running()) {
1121                 window->lock_window("EndRecordThread::~EndRecordThread");
1122                 window->set_done(1);
1123                 window->unlock_window();
1124         }
1125         Thread::join();
1126 }
1127
1128 void EndRecordThread::start(int is_ok)
1129 {
1130         this->is_ok = is_ok;
1131         if( gui->record->writing_file ) {
1132                 if(!running())
1133                         Thread::start();
1134         }
1135         else {
1136                 gui->set_done(!is_ok);
1137         }
1138 }
1139
1140 void EndRecordThread::run()
1141 {
1142         window = new QuestionWindow(gui->record->mwindow);
1143         window->create_objects(_("Interrupt recording in progress?"), 0);
1144         int result = window->run_window();
1145         delete window;
1146         if(result == 2) gui->set_done(!is_ok);
1147 }
1148
1149
1150 RecordStartoverThread::RecordStartoverThread(RecordGUI *gui)
1151  : Thread(1, 0, 0)
1152 {
1153         this->gui = gui;
1154 }
1155 RecordStartoverThread::~RecordStartoverThread()
1156 {
1157         if(Thread::running()) {
1158                 window->lock_window("RecordStartoverThread::~RecordStartoverThread");
1159                 window->set_done(1);
1160                 window->unlock_window();
1161         }
1162         Thread::join();
1163 }
1164
1165 void RecordStartoverThread::run()
1166 {
1167         Record *record = gui->record;
1168         window = new QuestionWindow(record->mwindow);
1169         window->create_objects(_("Rewind batch and overwrite?"), 0);
1170         int result = window->run_window();
1171         if(result == 2) record->start_over();
1172         delete window;
1173 }
1174
1175
1176 int RecordGUI::set_translation(int x, int y, float z)
1177 {
1178         record->video_x = x;
1179         record->video_y = y;
1180         record->video_zoom = z;
1181         return 0;
1182 }
1183
1184 void RecordGUI::reset_video()
1185 {
1186         total_dropped_frames = 0;
1187         status_thread->reset_video();
1188         update_framerate(record->default_asset->frame_rate);
1189 }
1190
1191 void RecordGUI::update_dropped_frames(long value)
1192 {
1193         status_thread->update_dropped_frames(value);
1194 }
1195
1196 void RecordGUI::update_frames_behind(long value)
1197 {
1198         status_thread->update_frames_behind(value);
1199 }
1200
1201 void RecordGUI::update_position(double value)
1202 {
1203         status_thread->update_position(value);
1204 }
1205
1206 void RecordGUI::update_framerate(double value)
1207 {
1208         status_thread->update_framerate(value);
1209 }
1210
1211 void RecordGUI::update_video(int dropped, int behind)
1212 {
1213         total_dropped_frames += dropped;
1214         update_dropped_frames(total_dropped_frames);
1215         update_frames_behind(behind);
1216         status_thread->update_position(record->current_display_position());
1217 }
1218
1219 void RecordGUI::reset_audio()
1220 {
1221 //      gui->lock_window("RecordAudio::run 2");
1222 // reset meter
1223         total_clipped_samples = 0;
1224         status_thread->reset_audio();
1225         AudioDevice *adevice = record->adevice;
1226         RecordMonitorGUI *window = record->record_monitor->window;
1227         window->lock_window("RecordAudio::run 2");
1228         MeterPanel *meters = window->meters;
1229         if( meters ) {
1230                 int dmix = adevice && (adevice->get_idmix() || adevice->get_odmix());
1231                 meters->init_meters(dmix);
1232         }
1233         window->unlock_window();
1234 //      gui->unlock_window();
1235 }
1236
1237 void RecordGUI::update_clipped_samples(long value)
1238 {
1239         status_thread->update_clipped_samples(value);
1240 }
1241
1242 void RecordGUI::update_audio(int channels, double *max, int *over)
1243 {
1244 // Get clipping status
1245         int clipped = 0;
1246         for( int ch=0; ch<channels && !clipped; ++ch )
1247                 if( over[ch] ) clipped = 1;
1248         if( clipped ) {
1249                 update_clipped_samples(++total_clipped_samples);
1250         }
1251 // Update meters if monitoring
1252         if( record->metering_audio ) {
1253                 RecordMonitorGUI *window = record->record_monitor->window;
1254                 window->lock_window("RecordAudio::run 1");
1255                 MeterPanel *meters = window->meters;
1256                 int nmeters = meters->meters.total;
1257                 for( int ch=0; ch<nmeters; ++ch ) {
1258                         double vmax = ch < channels ? max[ch] : 0.;
1259                         int   vover = ch < channels ? over[ch] : 0;
1260                         meters->meters.values[ch]->update(vmax, vover);
1261                 }
1262                 window->unlock_window();
1263         }
1264 // update position, if no video
1265         if( !record->default_asset->video_data )
1266                 update_position(record->current_display_position());
1267 }
1268
1269
1270 int RecordGUI::keypress_event()
1271 {
1272         if (get_keypress() != 'h' || ! alt_down() ||
1273             ! is_tooltip_event_win() || ! cursor_inside())
1274                 return record_transport->keypress_event();
1275
1276         context_help_show("Record Web Media");
1277         return 1;
1278 }
1279
1280 void RecordGUI::update_labels(double new_position)
1281 {
1282         RecordLabel *prev, *next;
1283
1284         for(prev = record->get_current_batch()->labels->last;
1285                 prev;
1286                 prev = prev->previous) {
1287                 if(prev->position <= new_position) break;
1288         }
1289
1290         for(next = record->get_current_batch()->labels->first;
1291                 next;
1292                 next = next->next)
1293         {
1294                 if(next->position > new_position) break;
1295         }
1296
1297         if(prev)
1298                 update_title(prev_label_title, prev->position);
1299         else
1300                 update_title(prev_label_title, -1);
1301
1302 //      if(next)
1303 //              update_title(next_label_title, (double)next->position / record->default_asset->sample_rate);
1304 //      else
1305 //              update_title(next_label_title, -1);
1306 }
1307
1308
1309 int RecordGUI::update_prev_label(long new_position)
1310 {
1311         update_title(prev_label_title, new_position);
1312         return 0;
1313 }
1314
1315 // int RecordGUI::update_next_label(long new_position)
1316 // {
1317 //      update_title(next_label_title, new_position);
1318 // }
1319 //
1320 int RecordGUI::update_title(BC_Title *title, double position)
1321 {
1322         static char string[256];
1323
1324         if(position >= 0) {
1325                 Units::totext(string,
1326                                 position,
1327                                 mwindow->edl->session->time_format,
1328                                 record->default_asset->sample_rate,
1329                                 record->default_asset->frame_rate,
1330                                 mwindow->edl->session->frames_per_foot);
1331         }
1332         else {
1333                 sprintf(string, "-");
1334         }
1335         title->update(string);
1336         return 0;
1337 }
1338
1339
1340 void RecordGUI::update_cron_status(const char *status)
1341 {
1342         lock_window("RecordGUI::update_cron_status");
1343         cron_status->update(status);
1344         unlock_window();
1345 }
1346
1347 void RecordGUI::update_power_off(int value)
1348 {
1349         lock_window("RecordGUI::update_power_off");
1350         power_off->update(value);
1351         unlock_window();
1352 }
1353
1354
1355
1356
1357 // ===================================== GUI
1358 // ================================================== modes
1359
1360 RecordGUIModeTextBox::RecordGUIModeTextBox(RecordGUIModeMenu *mode_menu,
1361                 int x, int y, int w,const char *text)
1362  : BC_TextBox(x, y, w, 1, text)
1363 {
1364         this->mode_menu = mode_menu;
1365 }
1366
1367 RecordGUIModeTextBox::~RecordGUIModeTextBox()
1368 {
1369 }
1370
1371 int RecordGUIModeTextBox::handle_event()
1372 {
1373         return 0;
1374 }
1375
1376 RecordGUIModeListBox::RecordGUIModeListBox(RecordGUIModeMenu *mode_menu)
1377  : BC_ListBox(mode_menu->textbox->get_x() + mode_menu->textbox->get_w(),
1378                 mode_menu->textbox->get_y(), xS(100), yS(50), LISTBOX_TEXT,
1379                 &mode_menu->modes, 0, 0, 1, 0, 1)
1380 {
1381         this->mode_menu = mode_menu;
1382 }
1383
1384 RecordGUIModeListBox::~RecordGUIModeListBox()
1385 {
1386 }
1387
1388 int RecordGUIModeListBox::handle_event()
1389 {
1390         return mode_menu->handle_event();
1391 }
1392
1393 RecordGUIModeMenu::RecordGUIModeMenu(RecordGUI *record_gui,
1394                 int x, int y, int w,const char *text)
1395 {
1396         this->record_gui = record_gui;
1397         textbox = new RecordGUIModeTextBox(this,x, y, w, "");
1398         record_gui->add_subwindow(textbox);
1399         listbox = new RecordGUIModeListBox(this);
1400         record_gui->add_subwindow(listbox);
1401 }
1402
1403 RecordGUIModeMenu::~RecordGUIModeMenu()
1404 {
1405         for( int i=0; i<modes.total; ++i )
1406                 delete modes.values[i];
1407         delete listbox;
1408         delete textbox;
1409 }
1410
1411 void RecordGUIModeMenu::create_objects()
1412 {
1413         value = RECORD_UNTIMED;
1414         modes.append(new BC_ListBoxItem(Batch::mode_to_text(RECORD_UNTIMED)));
1415         modes.append(new BC_ListBoxItem(Batch::mode_to_text(RECORD_TIMED)));
1416         textbox->update(modes.values[value]->get_text());
1417 }
1418
1419 int RecordGUIModeMenu::handle_event()
1420 {
1421         value = listbox->get_selection_number(0, 0);
1422         textbox->update(modes.values[value]->get_text());
1423         textbox->handle_event();
1424         record_gui->record->set_record_mode(value);
1425         if( value == RECORD_TIMED )
1426                 record_gui->batch_duration->enable();
1427         else
1428                 record_gui->batch_duration->disable();
1429         return 0;
1430 }
1431
1432 void RecordGUIModeMenu::update(int value)
1433 {
1434         this->value = value;
1435         textbox->update(modes.values[value]->get_text());
1436 }
1437
1438 int RecordGUIModeMenu::get_w()
1439 {
1440         return textbox->get_w() + listbox->get_w();
1441 }
1442
1443 int RecordGUIModeMenu::get_h()
1444 {
1445         return MAX(textbox->get_h(), listbox->get_h());
1446 }
1447
1448
1449 RecordStatusThread::RecordStatusThread(MWindow *mwindow, RecordGUI *gui)
1450  : Thread(1, 0, 0)
1451 {
1452         this->mwindow = mwindow;
1453         this->gui = gui;
1454         input_lock = new Condition(0, "RecordStatusThread::input_lock");
1455         reset_video();
1456         reset_audio();
1457         window_locked = 0;
1458         done = 0;
1459 }
1460
1461 RecordStatusThread::~RecordStatusThread()
1462 {
1463         if(Thread::running())
1464         {
1465                 done = 1;
1466                 input_lock->unlock();
1467         }
1468         Thread::join();
1469         delete input_lock;
1470 }
1471
1472 void RecordStatusThread::reset_video()
1473 {
1474         new_dropped_frames = 0;
1475         displayed_dropped_frames = -1;
1476         new_frames_behind = 0;
1477         displayed_frames_behind = -1;
1478         new_position = 0;
1479         displayed_framerate = -1.;
1480         new_framerate = 0.;
1481 }
1482
1483 void RecordStatusThread::reset_audio()
1484 {
1485         new_clipped_samples = 0;
1486         displayed_clipped_samples = -1;
1487 }
1488
1489 void RecordStatusThread::update_frames_behind(long value)
1490 {
1491         if( value != displayed_frames_behind ) {
1492                 new_frames_behind = value;
1493                 input_lock->unlock();
1494         }
1495 }
1496
1497 void RecordStatusThread::update_dropped_frames(long value)
1498 {
1499         if( value != displayed_dropped_frames ) {
1500                 new_dropped_frames = value;
1501                 input_lock->unlock();
1502         }
1503 }
1504
1505 void RecordStatusThread::update_clipped_samples(long value)
1506 {
1507         if( value != displayed_clipped_samples ) {
1508                 new_clipped_samples = value;
1509                 input_lock->unlock();
1510         }
1511 }
1512
1513 void RecordStatusThread::update_position(double value)
1514 {
1515         this->new_position = value;
1516         input_lock->unlock();
1517 }
1518
1519 void RecordStatusThread::update_framerate(double value)
1520 {
1521         if( value != displayed_framerate ) {
1522                 new_framerate = value;
1523                 input_lock->unlock();
1524         }
1525 }
1526
1527 void RecordStatusThread::get_window_lock()
1528 {
1529         if( !window_locked ) {
1530                 gui->lock_window("RecordStatusThread::run 1");
1531                 window_locked = 1;
1532         }
1533 }
1534
1535 template<class T>
1536 void RecordStatusThread::
1537 update_status_string(const char *fmt, T &new_value, T &displayed_value, BC_Title *widgit)
1538 {
1539         if( new_value >= 0 ) {
1540                 if( displayed_value != new_value ) {
1541                         displayed_value = new_value;
1542                         if( widgit ) {
1543                                 char string[64];
1544                                 sprintf(string, fmt, displayed_value);
1545                                 get_window_lock();
1546                                 widgit->update(string);
1547                         }
1548                 }
1549                 new_value = -1;
1550         }
1551 }
1552
1553 void RecordStatusThread::run()
1554 {
1555         while(!done) {
1556                 input_lock->lock("RecordStatusThread::run");
1557                 if(done) break;
1558                 update_status_string("%d", new_dropped_frames, displayed_dropped_frames,
1559                                         gui->frames_dropped);
1560                 update_status_string("%d", new_frames_behind, displayed_frames_behind,
1561                                         gui->frames_behind);
1562                 update_status_string("%d", new_clipped_samples, displayed_clipped_samples,
1563                                         gui->samples_clipped);
1564                 update_status_string("%0.2f", new_framerate, displayed_framerate,
1565                                         gui->framerate);
1566                 if( new_position >= 0 ) {
1567                         get_window_lock();
1568                         gui->update_title(gui->position_title, new_position);
1569                         gui->update_labels(new_position);
1570                         new_position = -1;
1571                 }
1572                 if( window_locked ) {
1573                         gui->unlock_window();
1574                         window_locked = 0;
1575                 }
1576         }
1577 }
1578
1579
1580 void RecordGUI::start_flash_batch()
1581 {
1582         if( batch_flash ) return;
1583         batch_flash = new RecordGUIFlash(this);
1584 }
1585
1586 void RecordGUI::stop_flash_batch()
1587 {
1588         if( !batch_flash ) return;
1589         delete batch_flash;
1590         batch_flash = 0;
1591 }
1592
1593 void RecordGUI::flash_batch()
1594 {
1595         lock_window("void RecordGUI::flash_batch");
1596         int cur_batch = record->current_batch();
1597         if( cur_batch >= 0 && cur_batch < batch_bay->count()) {
1598                 flash_color = flash_color == GREEN ? RED : GREEN;
1599 //printf("RecordGUI::flash_batch %x\n", flash_color);
1600                 batch_bay->set_row_color(cur_batch, flash_color);
1601                 batch_bay->update_batch_news(cur_batch);
1602         }
1603         unlock_window();
1604 }
1605
1606 RecordGUIFlash::
1607 RecordGUIFlash(RecordGUI *record_gui)
1608  : Thread(1, 0, 0)
1609 {
1610         this->record_gui = record_gui;
1611         flash_lock = new Condition(0,"RecordGUIFlash::flash_lock");
1612         done = 0;
1613         Thread::start();
1614 }
1615
1616 RecordGUIFlash::
1617 ~RecordGUIFlash()
1618 {
1619         if( Thread::running() ) {
1620                 done = 1;
1621                 flash_lock->unlock();
1622                 Thread::cancel();
1623         }
1624         Thread::join();
1625         delete flash_lock;
1626 }
1627
1628 void RecordGUIFlash::run()
1629 {
1630         while( !done ) {
1631                 record_gui->flash_batch();
1632                 enable_cancel();
1633                 Timer::delay(500);
1634                 disable_cancel();
1635         }
1636 }
1637
1638
1639
1640 RecordGUIDCOffset::RecordGUIDCOffset(MWindow *mwindow, int y)
1641  : BC_Button(xS(230), y, mwindow->theme->calibrate_data)
1642 {
1643 }
1644
1645 RecordGUIDCOffset::~RecordGUIDCOffset() {}
1646
1647 int RecordGUIDCOffset::handle_event()
1648 {
1649         return 1;
1650 }
1651
1652 int RecordGUIDCOffset::keypress_event() { return context_help_check_and_show(); }
1653
1654 RecordGUIDCOffsetText::RecordGUIDCOffsetText(char *text, int y, int number)
1655  : BC_TextBox(xS(30), y+yS(1), xS(67), 1, text, 0)
1656 {
1657         this->number = number;
1658 }
1659
1660 RecordGUIDCOffsetText::~RecordGUIDCOffsetText()
1661 {
1662 }
1663
1664 int RecordGUIDCOffsetText::handle_event()
1665 {
1666         return 1;
1667 }
1668
1669 RecordGUIReset::RecordGUIReset(MWindow *mwindow, RecordGUI *gui, int y)
1670  : BC_Button(xS(400), y, mwindow->theme->over_button)
1671 { this->gui = gui; }
1672
1673 RecordGUIReset::~RecordGUIReset()
1674 {
1675 }
1676
1677 int RecordGUIReset::handle_event()
1678 {
1679         return 1;
1680 }
1681
1682 RecordGUIResetTranslation::RecordGUIResetTranslation(MWindow *mwindow, RecordGUI *gui, int y)
1683  : BC_Button(xS(250), y, mwindow->theme->reset_data)
1684 {
1685         this->gui = gui;
1686 }
1687
1688 RecordGUIResetTranslation::~RecordGUIResetTranslation()
1689 {
1690 }
1691
1692 int RecordGUIResetTranslation::handle_event()
1693 {
1694         gui->set_translation(0, 0, 1);
1695         return 1;
1696 }
1697