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