record batch dir path fix, handle yuv in gl masking, sync up maskengine/playback3d...
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / recordbatches.C
1 #include <stdio.h>
2 #include <stdint.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5 #include <string.h>
6 #include <fcntl.h>
7
8 #include "asset.h"
9 #include "batch.h"
10 #include "bchash.h"
11 #include "bclistbox.h"
12 #include "channel.h"
13 #include "channeldb.h"
14 #include "filesystem.h"
15 #include "mwindow.h"
16 #include "record.h"
17 #include "recordbatches.h"
18 #include "timeentry.h"
19
20 const char * RecordBatches::
21 default_batch_titles[] = {
22         N_("On"), N_("Path"), N_("News"), N_("Start time"),
23         N_("Duration"), N_("Source"), N_("Mode")
24 };
25
26 const int RecordBatches::
27 default_columnwidth[] = {
28         30, 200, 100, 100, 100, 100, 70
29 };
30
31 void RecordBatches::
32 load_defaults(ChannelDB * channeldb, Record * record)
33 {
34         char string[BCTEXTLEN];
35         BC_Hash *defaults = mwindow->defaults;
36         defaults->get("RECORD_DEFAULT_DIRECTORY", default_directory);
37         early_margin = defaults->get("RECORD_EARLY_MARGIN", early_margin);
38         late_margin = defaults->get("RECORD_LATE_MARGIN", late_margin);
39         for(int i = 0; i < BATCH_COLUMNS; i++) {
40                 batch_titles[i] = _(default_batch_titles[i]);
41                 sprintf(string, "BATCH_COLUMNWIDTH_%d", i);
42                 column_widths[i] = defaults->get(string, default_columnwidth[i]);
43         }
44         int total_batches = defaults->get("TOTAL_BATCHES", 1);
45         if(total_batches < 1) total_batches = 1;
46         for(int i = 0; i < total_batches; ++i) {
47                 Batch *batch = new Batch(mwindow, record);
48                 batch->create_objects();
49                 batches.append(batch);
50                 Asset *asset = batch->asset;
51                 sprintf(string, "RECORD_PATH_%d", i);
52                 defaults->get(string, asset->path);
53                 sprintf(string, "RECORD_CHANNEL_%d", i);
54                 int chan_no = channeldb->number_of(batch->channel);
55                 chan_no = defaults->get(string, chan_no);
56                 batch->channel = channeldb->get(chan_no);
57                 sprintf(string, "RECORD_STARTDAY_%d", i);
58                 batch->start_day = defaults->get(string, batch->start_day);
59                 sprintf(string, "RECORD_STARTTIME_%d", i);
60                 batch->start_time = defaults->get(string, batch->start_time);
61                 sprintf(string, "RECORD_DURATION_%d", i);
62                 batch->duration = defaults->get(string, batch->duration);
63                 sprintf(string, "RECORD_MODE_%d", i);
64                 batch->record_mode = defaults->get(string, batch->record_mode);
65                 sprintf(string, "BATCH_ENABLED_%d", i);
66                 batch->enabled = defaults->get(string, batch->enabled);
67                 batch->update_times();
68         }
69
70         current_item = editing_item = 0;
71 }
72
73 void RecordBatches::
74 save_defaults(ChannelDB * channeldb)
75 {
76         char string[BCTEXTLEN];
77         BC_Hash *defaults = mwindow->defaults;
78         defaults->update("RECORD_DEFAULT_DIRECTORY", default_directory);
79         defaults->update("RECORD_EARLY_MARGIN", early_margin);
80         defaults->update("RECORD_LATE_MARGIN", late_margin);
81         for(int i = 0; i < BATCH_COLUMNS; i++) {
82                 sprintf(string, "BATCH_COLUMNWIDTH_%d", i);
83                 defaults->update(string, column_widths[i]);
84         }
85
86         defaults->update("TOTAL_BATCHES", batches.total);
87         for(int i = 0; i < batches.total; ++i) {
88                 Batch *batch = batches.values[i];
89                 Asset *asset = batch->asset;
90                 sprintf(string, "RECORD_PATH_%d", i);
91                 defaults->update(string, asset->path);
92                 sprintf(string, "RECORD_CHANNEL_%d", i);
93                 int chan_no = channeldb->number_of(batch->channel);
94                 defaults->update(string, chan_no);
95                 sprintf(string, "RECORD_STARTDAY_%d", i);
96                 defaults->update(string, batch->start_day);
97                 sprintf(string, "RECORD_STARTTIME_%d", i);
98                 defaults->update(string, batch->start_time);
99                 sprintf(string, "RECORD_DURATION_%d", i);
100                 defaults->update(string, batch->duration);
101                 sprintf(string, "RECORD_MODE_%d", i);
102                 defaults->update(string, batch->record_mode);
103                 sprintf(string, "BATCH_ENABLED_%d", i);
104                 defaults->update(string, batch->enabled);
105         }
106 }
107
108 void RecordBatches::
109 save_default_channel(ChannelDB * channeldb)
110 {
111         BC_Hash *defaults = mwindow->defaults;
112         Batch *batch = get_editing_batch();
113         if( !batch ) return;
114         int chan_no = channeldb->number_of(batch->channel);
115         if( chan_no < 0 ) return;
116         defaults->update("RECORD_CURRENT_CHANNEL", chan_no);
117 }
118
119 RecordBatches::
120 RecordBatches(MWindow * mwindow)
121 {
122         this->mwindow = mwindow;
123         editing_item = current_item = -1;
124         batch_active = 0;
125         early_margin = late_margin = 0.;
126         default_directory[0] = 0;
127 }
128
129 RecordBatches::
130 ~RecordBatches()
131 {
132 }
133
134 void RecordBatches::
135 remove(Batch *batch)
136 {
137         batches.remove(batch);
138         int total_batches = total();
139         if( current_item == editing_item ) {
140                 if(current_item >= total_batches)
141                         current_item = total_batches - 1;
142                 editing_item = current_item;
143         }
144         else {
145                 if(current_item > editing_item)
146                         --current_item;
147                 if( editing_item >= total_batches )
148                         editing_item = total_batches - 1;
149         }
150 }
151
152 void RecordBatches::
153 clear()
154 {
155         batches.remove_all_objects();
156         for(int j = 0; j < BATCH_COLUMNS; j++) {
157                 data[j].remove_all_objects();
158         }
159         current_item = editing_item = -1;
160 }
161
162 RecordBatchesGUI::
163 RecordBatchesGUI(RecordBatches &batches,
164         int x, int y, int w, int h)
165  : BC_ListBox(x, y, w, h, LISTBOX_TEXT,         // Display text list or icons
166                         batches.data,           // Each column has an ArrayList of BC_ListBoxItems.
167                         batches.batch_titles,   // Titles for columns.  Set to 0 for no titles
168                         batches.column_widths,  // width of each column
169                         BATCH_COLUMNS,          // Total columns.
170                         0,                      // Pixel of top of window.
171                         0,                      // If this listbox is a popup window
172                         LISTBOX_SINGLE,         // Select one item or multiple items
173                         ICON_LEFT,              // Position of icon relative to text of each item
174                         1),                     // Allow dragging
175    batches(batches)
176 {
177         dragging_item = 0;
178 }
179
180 // Do nothing for double clicks to protect active batch
181 int RecordBatchesGUI::
182 handle_event()
183 {
184         return 1;
185 }
186
187 int RecordBatchesGUI::
188 update(int highlighted_item, int recalc_positions)
189 {
190         return BC_ListBox::update(batches.data, batches.batch_titles,
191                         batches.column_widths, BATCH_COLUMNS,
192                         get_xposition(), get_yposition(),
193                         highlighted_item, recalc_positions);
194 }
195
196 int RecordBatchesGUI::
197 column_resize_event()
198 {
199         for(int i = 0; i < BATCH_COLUMNS; i++) {
200                 batches.column_widths[i] = get_column_width(i);
201         }
202         return 1;
203 }
204
205 int RecordBatchesGUI::
206 drag_start_event()
207 {
208         if(!BC_ListBox::drag_start_event()) return 0;
209         dragging_item = 1;
210         return 1;
211 }
212
213 int RecordBatchesGUI::
214 drag_motion_event()
215 {
216         if(!BC_ListBox::drag_motion_event()) return 0;
217         return 1;
218 }
219
220 int RecordBatchesGUI::
221 selection_changed()
222 {
223         int n = get_selection_number(0, 0);
224         if(n >= 0) {
225                 set_editing_batch(n);
226                 if(get_cursor_x() < batches.column_widths[0]) {
227                         Batch *batch = batches[n];
228                         batch->enabled = !batch->enabled;
229                         update_batches(n);
230                 }
231         }
232         return 1;
233 }
234
235 int RecordBatchesGUI::
236 drag_stop_event()
237 {
238         if(dragging_item) {
239                 int total_batches = batches.total();
240                 int src_item = editing_batch();
241                 Batch *src_batch = batches[src_item];
242                 int dst_item = get_highlighted_item();
243                 if(dst_item < 0) dst_item = total_batches;
244                 if(dst_item > src_item) --dst_item;
245
246                 for(int i = src_item; i < total_batches - 1; i++)
247                         batches[i] = batches[i + 1];
248                 for(int i = total_batches - 1; i > dst_item; --i)
249                         batches[i] = batches[i - 1];
250                 batches[dst_item] = src_batch;
251
252                 BC_ListBox::drag_stop_event();
253                 dragging_item = 0;
254                 set_editing_batch(dst_item);
255                 update_batches(dst_item);
256         }
257         return 0;
258 }
259
260 void RecordBatchesGUI::
261 update_batch_news(int item)
262 {
263         Batch *batch = batches[item];
264         batch->calculate_news();
265         batches.data[2].values[item]->set_text(batch->news);
266         update();  flush();
267 }
268
269 void RecordBatchesGUI::
270 update_batches(int selection_item)
271 {
272         time_t t;  time(&t);
273         char string[BCTEXTLEN], string2[BCTEXTLEN];
274
275         for(int j = 0; j < BATCH_COLUMNS; j++) {
276                 batches.data[j].remove_all_objects();
277         }
278         int total_batches = batches.total();
279         for(int i = 0; i < total_batches; i++) {
280                 Batch *batch = batches[i];
281                 batch->update_times();
282                 batch->calculate_news();
283
284                 int color = LTGREEN;
285                 if( i != batches.current_item ) {
286                         if( batch->time_start < t )
287                                 color = RED;
288                         else if( i > 0 && batches[i-1]->time_end > batch->time_start )
289                                 color = RED;
290                         else if( batch->time_start - t > 2*24*3600 )
291                                 color = YELLOW;
292                 }
293                 else
294                         color = LTYELLOW;
295
296                 batches.data[0].append(
297                         new BC_ListBoxItem((char *)(batch->enabled ? "X" : " "), color));
298                 batches.data[1].append(
299                         new BC_ListBoxItem(batch->asset->path, color));
300                 batches.data[2].append(
301                         new BC_ListBoxItem(batch->news, RED));
302                 Units::totext(string2, batch->start_time, TIME_HMS3);
303                 sprintf(string, "%s %s", TimeEntry::day_table[batch->start_day], string2);
304                 batches.data[3].append(
305                         new BC_ListBoxItem(string, color));
306                 Units::totext(string, batch->duration, TIME_HMS3);
307                 batches.data[4].append(
308                         new BC_ListBoxItem(string, color));
309                 sprintf(string, "%s", batch->channel ? batch->channel->title : _("None"));
310                 batches.data[5].append(
311                         new BC_ListBoxItem(string, color));
312                 sprintf(string, "%s", Batch::mode_to_text(batch->record_mode));
313                 batches.data[6].append(
314                         new BC_ListBoxItem(string, color));
315
316                 if(i == selection_item) {
317                         for(int j = 0; j < BATCH_COLUMNS; j++) {
318                                 batches.data[j].values[i]->set_selected(1);
319                         }
320                 }
321         }
322         update(batches.editing_item, 1);
323         flush();
324 }
325
326 void RecordBatchesGUI::
327 set_row_color(int row, int color)
328 {
329         for(int i = 0; i < BATCH_COLUMNS; i++) {
330                 BC_ListBoxItem *batch = batches.data[i].values[row];
331                 batch->set_color(color);
332         }
333 }
334
335
336 RecordBatchesGUI::Dir::
337 Dir(RecordBatches &batches, const char *dir, int x, int y)
338  : BC_TextBox(x, y, 200, 1, dir),
339    batches(batches),
340    directory(batches.default_directory)
341 {
342         strncpy(directory, dir, sizeof(directory));
343         dir_entries = new ArrayList<BC_ListBoxItem*>;
344         entries_dir[0] = 0;
345         load_dirs(dir);
346 }
347
348 RecordBatchesGUI::Dir::
349 ~Dir()
350 {
351         dir_entries->remove_all_objects();
352         delete dir_entries;
353 }
354
355 int RecordBatchesGUI::Dir::
356 handle_event()
357 {
358         char *path = FileSystem::basepath(get_text());
359         strcpy(directory, path);
360         load_dirs(path);
361         calculate_suggestions(dir_entries);
362         delete [] path;
363         return 1;
364 }
365
366 void RecordBatchesGUI::Dir::
367 load_dirs(const char *dir)
368 {
369         if( !strncmp(dir, entries_dir, sizeof(entries_dir)) ) return;
370         strncpy(entries_dir, dir, sizeof(entries_dir));
371         dir_entries->remove_all_objects();
372         FileSystem fs;  fs.update(dir);
373         int total_files = fs.total_files();
374         for(int i = 0; i < total_files; i++) {
375                 if( !fs.get_entry(i)->get_is_dir() ) continue;
376                 const char *name = fs.get_entry(i)->get_name();
377                 dir_entries->append(new BC_ListBoxItem(name));
378         }
379 }
380
381 RecordBatchesGUI::Path::
382 Path(RecordBatches &batches, int x, int y)
383  : BC_TextBox(x, y, 200, 1, batches.get_editing_batch()->asset->path),
384    batches(batches)
385 {
386 }
387
388 RecordBatchesGUI::Path::
389 ~Path()
390 {
391 }
392
393 int RecordBatchesGUI::Path::
394 handle_event()
395 {
396         calculate_suggestions();
397         Batch *batch = batches.gui->get_editing_batch();
398         strcpy(batch->asset->path, get_text());
399         batches.gui->update_batches();
400         return 1;
401 }
402
403 RecordBatchesGUI::StartTime::
404 StartTime(BC_Window *win, RecordBatches &batches, int x, int y, int w)
405  : TimeEntry(win, x, y,
406                  &batches.get_editing_batch()->start_day,
407                  &batches.get_editing_batch()->start_time, TIME_HMS3, w),
408    batches(batches)
409 {
410 }
411
412 int RecordBatchesGUI::StartTime::
413 handle_event()
414 {
415         batches.gui->update_batches();
416         return 1;
417 }
418
419
420 RecordBatchesGUI::Duration::
421 Duration(BC_Window *win, RecordBatches &batches, int x, int y, int w)
422  : TimeEntry(win, x, y, 0,
423                  &batches.get_editing_batch()->duration, TIME_HMS2, w),
424    batches(batches)
425 {
426 }
427
428 int RecordBatchesGUI::Duration::
429 handle_event()
430 {
431         batches.gui->update_batches();
432         return 1;
433 }
434
435
436 RecordBatchesGUI::Source::
437 Source(BC_Window *win, RecordBatches &batches, int x, int y)
438  : BC_PopupTextBox(win, &sources,
439                  batches.get_editing_batch()->get_source_text(),
440                  x, y, 200, 200),
441    batches(batches)
442 {
443 }
444
445 int RecordBatchesGUI::Source::
446 handle_event()
447 {
448         batches.gui->update_batches();
449         return 1;
450 }
451
452
453 RecordBatchesGUI::News::
454 News(RecordBatches &batches, int x, int y)
455  : BC_TextBox(x, y, 200, 1, batches.get_editing_batch()->news),
456    batches(batches)
457 {
458 }
459
460 int RecordBatchesGUI::News::
461 handle_event()
462 {
463         return 1;
464 }
465
466
467 RecordBatchesGUI::NewBatch::
468 NewBatch(RecordBatches &batches, int x, int y)
469  : BC_GenericButton(x, y, _("New")),
470    batches(batches)
471 {
472         set_tooltip(_("Create new clip."));
473 }
474
475 int RecordBatchesGUI::NewBatch::
476 handle_event()
477 {
478         int new_item = batches.total()-1;
479         batches.editing_item = new_item;
480         batches.gui->update_batches(new_item);
481         return 1;
482 }
483
484
485 RecordBatchesGUI::DeleteBatch::
486 DeleteBatch(RecordBatches &batches, int x, int y)
487  : BC_GenericButton(x, y, _("Delete")),
488    batches(batches)
489 {
490         set_tooltip(_("Delete clip."));
491 }
492
493 int RecordBatchesGUI::DeleteBatch::
494 handle_event()
495 {
496         batches.gui->update_batches();
497         return 1;
498 }
499
500
501 RecordBatchesGUI::StartBatches::
502 StartBatches(RecordBatches &batches, int x, int y)
503  : BC_GenericButton(x, y, _("Start")), batches(batches)
504 {
505         set_tooltip(_("Start batch recording\nfrom the current position."));
506 }
507
508 int RecordBatchesGUI::StartBatches::
509 handle_event()
510 {
511         batches.batch_active = 1;
512         return 1;
513 }
514
515
516 RecordBatchesGUI::StopBatches::
517 StopBatches(RecordBatches &batches, int x, int y)
518  : BC_GenericButton(x, y, _("Stop")), batches(batches)
519 {
520 }
521
522 int RecordBatchesGUI::StopBatches::
523 handle_event()
524 {
525         batches.batch_active = 0;
526         return 1;
527 }
528
529
530 RecordBatchesGUI::ActivateBatch::
531 ActivateBatch(RecordBatches &batches, int x, int y)
532  : BC_GenericButton(x, y, _("Activate")), batches(batches)
533 {
534         set_tooltip(_("Make the highlighted\nclip active."));
535 }
536
537 int RecordBatchesGUI::ActivateBatch::
538 handle_event()
539 {
540         return 1;
541 }
542
543
544 RecordBatchesGUI::ClearBatch::
545 ClearBatch(RecordBatches &batches, int x, int y)
546  : BC_GenericButton(x, y, _("Clear")), batches(batches)
547 {
548         set_tooltip(_("Delete all clips."));
549 }
550
551 int RecordBatchesGUI::ClearBatch::
552 handle_event()
553 {
554         batches.gui->update_batches();
555         return 1;
556 }
557