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