32fd02aa82fb41a632de925d9d488b66619cb240
[goodguy/history.git] / cinelerra-5.1 / cinelerra / binfolder.C
1 /*
2  * CINELERRA
3  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  */
20
21 #include "awindowgui.h"
22 #include "bchash.h"
23 #include "binfolder.h"
24 #include "cstrdup.h"
25 #include "edl.h"
26 #include "filexml.h"
27 #include "guicast.h"
28 #include "indexable.h"
29 #include "language.h"
30 #include "localsession.h"
31 #include "mainerror.h"
32 #include "mainsession.h"
33 #include "mutex.h"
34 #include "mwindow.h"
35
36 #include <time.h>
37
38 const char *BinFolderEnabled::types[] = {
39         N_("Off"),
40         N_("And"),
41         N_("Or"),
42         N_("And Not"),
43         N_("Or Not"),
44 };
45
46 const char *BinFolderTarget::types[] = {
47         N_("Patterns"),
48         N_("Filesize"),
49         N_("Time"),
50         N_("Track type"),
51         N_("Width"),
52         N_("Height"),
53         N_("Framerate"),
54         N_("Samplerate"),
55         N_("Channels"),
56         N_("Duration"),
57 };
58
59 const char *BinFolderOp::types[] = {
60         N_("Around"),
61         N_("Eq  =="),
62         N_("Ge  >="),
63         N_("Gt  > "),
64         N_("Ne  !="),
65         N_("Le  <="),
66         N_("Lt  < "),
67         N_("Matches"),
68 };
69
70 static const struct {
71         const char *sfx, *sfxs;
72         double radix;
73 } scan_ranges[] = {
74         { N_("min"),   N_("mins"),   60, },
75         { N_("hour"),  N_("hours"),  60*60, },
76         { N_("day"),   N_("days"),   24*60*60, },
77         { N_("week"),  N_("weeks"),  24*60*60*7, },
78         { N_("month"), N_("months"), 24*60*60*31, },
79         { N_("year"),  N_("years"),  24*60*60*365.25, },
80 };
81 #define SCAN_RANGE_DAYS 2
82 #define DBL_INF 9007199254740991.
83
84 static int scan_inf(const char *cp, char *&bp)
85 {
86         bp = (char *)cp;
87         const char *inf = _("inf");
88         const int linf = strlen(inf);
89         if( strncasecmp(cp,inf,linf) ) return 0;
90         bp = (char *)(cp + linf);
91         return 1;
92 }
93
94 static double scan_no(const char *cp, char *&bp)
95 {
96         while( *cp == ' ' ) ++cp;
97         if( scan_inf(cp, bp) ) return DBL_INF;
98         if( *cp == '+' ) return 0;
99         double v = strtod(cp, &bp);
100         switch( *bp ) {
101         case 'T': v *= 1099511627776.;  break;
102         case 't': v *= 1e12;            break;
103         case 'G': v *= 1073741824.;     break;
104         case 'g': v *= 1e9;             break;
105         case 'M': v *= 1048576.;        break;
106         case 'm': v *= 1e6;             break;
107         case 'K': v *= 1024.;           break;
108         case 'k': v *= 1e3;             break;
109         default:  return v;
110         }
111         ++bp;
112         return v;
113 }
114
115 static void scan_around(const char *cp, char *&bp, double &v, double &a)
116 {
117         v = 0;  a = -1;
118         double sv = scan_no(cp, bp);
119         if( bp > cp ) v = sv;
120         if( *bp == '+' ) {
121                 double sa = scan_no(cp=bp+1, bp);
122                 if( bp > cp ) a = sa;
123         }
124 }
125
126 static void show_no(double v, char *&cp, char *ep, const char *fmt="%0.0f")
127 {
128         if( v == DBL_INF ) {
129                 cp += snprintf(cp, ep-cp, "%s", _("inf"));
130                 return;
131         }
132         const char *sfx = 0;
133         static const struct { double radix; const char *sfx; } sfxs[] = {
134                 { 1024.,          "K" }, { 1e3,  "k" },
135                 { 1048576.,       "M" }, { 1e6,  "m" },
136                 { 1073741824.,    "G" }, { 1e9,  "g" },
137                 { 1099511627776., "T" }, { 1e12, "t" },
138         };
139         for( int i=sizeof(sfxs)/sizeof(sfxs[0]); --i>=0; ) {
140                 if( v < sfxs[i].radix ) continue;
141                 if( fmod(v, sfxs[i].radix) == 0 ) {
142                         v /= sfxs[i].radix;
143                         sfx = sfxs[i].sfx;
144                         break;
145                 }
146         }
147         cp += snprintf(cp, ep-cp, fmt, v);
148         if( sfx ) cp += snprintf(cp, ep-cp, "%s", sfx);
149 }
150
151 static double scan_duration(const char *cp, char *&bp)
152 {
153         if( scan_inf(cp, bp) ) return DBL_INF;
154         double secs = 0;
155         while( *cp ) {
156                 double v = strtod(cp, &bp);
157                 if( cp >= bp ) break;
158                 int k = sizeof(scan_ranges)/sizeof(scan_ranges[0]);
159                 while( --k >= 0 ) {
160                         const char *tsfx  = _(scan_ranges[k].sfx);
161                         int lsfx  = strlen(tsfx), msfx  = strncasecmp(bp, tsfx,  lsfx);
162                         const char *tsfxs = _(scan_ranges[k].sfxs);
163                         int lsfxs = strlen(tsfxs), msfxs = strncasecmp(bp, tsfxs, lsfxs);
164                         int len = !msfx && !msfxs ? (lsfx > lsfxs ? lsfx : lsfxs) :
165                                 !msfx ? lsfx : !msfxs ? lsfxs : -1;
166                         if( len >= 0 ) {
167                                 secs += v * scan_ranges[k].radix;
168                                 bp += len;
169                                 break;
170                         }
171                 }
172                 if( k < 0 ) {
173                         int hour = 0, mins = 0;
174                         if( *bp == ':' && v == (int)v ) {
175                                 mins = v;
176                                 v = strtod(cp=bp+1, &bp);
177                                 if( *bp == ':' && v == (int)v ) {
178                                         hour = mins;  mins = v;
179                                         v = strtod(cp=bp+1, &bp);
180                                 }
181                         }
182                         secs += hour*3600 + mins*60 + v;
183                 }
184                 while( *bp && (*bp<'0' || *bp>'9') ) ++bp;
185                 cp = bp;
186         }
187         return secs;
188 }
189
190 static void show_duration(double v, char *&cp, char *ep)
191 {
192         if( v == DBL_INF ) {
193                 cp += snprintf(cp, ep-cp, "%s", _("inf"));
194                 return;
195         }
196         double secs = v;  char *bp = cp;
197         int k = sizeof(scan_ranges)/sizeof(scan_ranges[0]);
198         while( --k >= SCAN_RANGE_DAYS ) {
199                 if( secs >= scan_ranges[k].radix ) {
200                         int v = secs/scan_ranges[k].radix;
201                         secs -= v * scan_ranges[k].radix;
202                         cp += snprintf(cp, ep-cp,"%d%s", v,
203                                 v > 1 ? _(scan_ranges[k].sfxs) : _(scan_ranges[k].sfx));
204                 }
205         }
206         if( secs > 0 ) {
207                 if( cp > bp && cp < ep ) *cp++ = ' ';
208                 int64_t n = secs; int hour = n/3600, min = (n/60)%60, sec = n%60;
209                 if( hour > 0 ) cp += snprintf(cp, ep-cp, "%d:", hour);
210                 if( hour > 0 || min > 0 ) cp += snprintf(cp, ep-cp, "%02d:", min);
211                 cp += snprintf(cp, ep-cp, n>=10 ? "%02d" : "%d", sec);
212         }
213 }
214
215 static int64_t scan_date(const char *cp, char *&bp)
216 {
217         double year=0, mon=1, day=1;
218         double hour=0, min=0;
219         bp = (char *)cp;
220         while( *bp == ' ' ) ++bp;
221         if( *bp == '+' ) return 0;
222         double secs = strtod(cp=bp, &bp);
223         if( *bp == '/' && secs == (int)secs ) {
224                 year = secs;  secs = 0;
225                 mon = strtod(cp=bp+1, &bp);
226                 if( *bp == '/' && mon == (int)mon ) {
227                         day = strtod(cp=bp+1, &bp);
228                         while( *bp == ' ' ) ++bp;
229                         secs = *bp != '+' ? strtod(cp=bp, &bp) : 0;
230                 }
231         }
232         if( *bp == ':' && secs == (int)secs ) {
233                 hour = secs;  secs = 0;
234                 min = strtod(cp=bp+1, &bp);
235                 if( *bp == ':' && min == (int)min ) {
236                         secs = strtod(cp=bp+1, &bp);
237                 }
238         }
239         struct tm ttm;  memset(&ttm, 0, sizeof(ttm));
240         ttm.tm_year = year-1900;  ttm.tm_mon = mon-1;  ttm.tm_mday = day;
241         ttm.tm_hour = hour;       ttm.tm_min = min;    ttm.tm_sec = secs;
242         ttm.tm_wday = ttm.tm_yday = 0;  ttm.tm_isdst = daylight; /* tzset in main */
243         time_t t = mktime(&ttm);
244         return (int64_t)t;
245 }
246
247 static void show_date(time_t t, char *&cp, char *ep)
248 {
249         struct tm tm;  localtime_r(&t, &tm);
250         cp += snprintf(cp, ep-cp, "%04d/%02d/%02d %02d:%02d:%02d",
251                 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
252                 tm.tm_hour, tm.tm_min, tm.tm_sec);
253 }
254
255 double BinFolder::matches_indexable(Indexable *idxbl)
256 {
257         double result = -1;
258         for( int i=0; i<filters.size(); ++i ) {
259                 BinFolderFilter *filter = filters[i];
260                 double ret = filter->op->test(filter->target, idxbl);
261                 switch( filter->enabled->type ) {
262                 case FOLDER_ENABLED_OR: {
263                         if( result < 0 ) result = ret;
264                         break; }
265                 case FOLDER_ENABLED_AND: {
266                         if( ret < 0 ) result = -1;
267                         break; }
268                 case FOLDER_ENABLED_OR_NOT: {
269                         if( ret < 0 ) result = 1;
270                         break; }
271                 case FOLDER_ENABLED_AND_NOT: {
272                         if( ret >= 0 ) result = -1;
273                         break; }
274                 }
275         }
276         return result;
277 }
278
279
280 BinFolder::BinFolder(int awindow_folder, int is_clips, const char *title)
281 {
282         this->awindow_folder = awindow_folder;
283         this->is_clips = is_clips;
284         char *bp = this->title;
285         int len = sizeof(this->title);
286         while( --len>0 && *title ) *bp++ = *title++;
287         *bp = 0;
288 }
289
290 BinFolder::BinFolder(BinFolder &that)
291 {
292         copy_from(&that);
293 }
294
295 void BinFolder::copy_from(BinFolder *that)
296 {
297         strcpy(title, that->title);
298         awindow_folder = that->awindow_folder;
299         is_clips = that->is_clips;
300         filters.copy_from(&that->filters);
301 }
302
303 BinFolder::~BinFolder()
304 {
305 }
306
307 void BinFolder::save_xml(FileXML *file)
308 {
309         file->tag.set_title("FOLDER");
310         file->tag.set_property("TITLE", title);
311         file->tag.set_property("AWINDOW_FOLDER", awindow_folder);
312         file->tag.set_property("IS_CLIPS", is_clips);
313         file->append_tag();
314         file->append_newline();
315         for( int i=0; i<filters.size(); ++i )
316                 filters[i]->save_xml(file);
317         file->tag.set_title("/FOLDER");
318         file->append_tag();
319         file->append_newline();
320 }
321
322 int BinFolder::load_xml(FileXML *file)
323 {
324         title[0] = 0;
325         file->tag.get_property("TITLE", title);
326         awindow_folder = file->tag.get_property("AWINDOW_FOLDER", -1);
327         is_clips = file->tag.get_property("IS_CLIPS", 0);
328         filters.remove_all_objects();
329
330         int ret = 0;
331         while( !(ret=file->read_tag()) ) {
332                 if( file->tag.title_is("/FOLDER") ) break;
333                 if( file->tag.title_is("FILTER") ) {
334                         BinFolderFilter *filter = new BinFolderFilter();
335                         filter->load_xml(file);
336                         filters.append(filter);
337                 }
338         }
339         return ret;
340 }
341
342 int BinFolder::add_patterns(ArrayList<Indexable*> *drag_idxbls)
343 {
344         int n = drag_idxbls->size();
345         if( !n ) return 1;
346         Indexable *idxbl;
347         int len = 0;
348         for( int i=0; i<n; ++i ) {
349                 idxbl = drag_idxbls->get(i);
350                 if( !idxbl->is_asset &&
351                     idxbl->awindow_folder == AW_PROXY_FOLDER )
352                         continue;
353                 len += strlen(idxbl->get_title()) + 1;
354         }
355         if( !len ) return 1;
356         char *pats = new char[len+1], *bp = pats;
357         for( int i=0; i<n; ++i ) {
358                 idxbl = drag_idxbls->get(i);
359                 if( !idxbl->is_asset &&
360                     idxbl->awindow_folder == AW_PROXY_FOLDER )
361                         continue;
362                 if( i > 0 ) *bp++ = '\n';
363                 const char *cp = idxbl->get_title();
364                 while( *cp ) *bp++ = *cp++;
365         }
366         *bp = 0;
367 // new pattern filter
368         BinFolderFilter *filter = new BinFolderFilter();
369         filter->update_enabled(FOLDER_ENABLED_OR);
370         filter->update_target(FOLDER_TARGET_PATTERNS);
371         filter->update_op(FOLDER_OP_MATCHES);
372         BinFolderTargetPatterns *patterns = (BinFolderTargetPatterns *)(filter->target);
373         patterns->update(pats);
374         filters.append(filter);
375         return 0;
376 }
377
378
379 double BinFolders::matches_indexable(int folder, Indexable *idxbl)
380 {
381         int k = size();
382         BinFolder *bin_folder = 0;
383         while( --k>=0 && (bin_folder=get(k)) && bin_folder->awindow_folder!=folder );
384         if( k < 0 ) return -1;
385         if( bin_folder->is_clips && idxbl->is_asset ) return -1;
386         if( !bin_folder->is_clips && !idxbl->is_asset ) return -1;
387         return bin_folder->matches_indexable(idxbl);
388 }
389
390 void BinFolders::save_xml(FileXML *file)
391 {
392         file->tag.set_title("FOLDERS");
393         file->append_tag();
394         file->append_newline();
395         for( int i=0; i<size(); ++i )
396                 get(i)->save_xml(file);
397         file->tag.set_title("/FOLDERS");
398         file->append_tag();
399         file->append_newline();
400 }
401
402 int BinFolders::load_xml(FileXML *file)
403 {
404         clear();
405         int ret = 0;
406         while( !(ret=file->read_tag()) ) {
407                 if( file->tag.title_is("/FOLDERS") ) break;
408                 if( file->tag.title_is("FOLDER") ) {
409                         BinFolder *folder = new BinFolder(-1, -1, "folder");
410                         folder->load_xml(file);
411                         append(folder);
412                 }
413         }
414         return ret;
415 }
416
417 void BinFolders::copy_from(BinFolders *that)
418 {
419         clear();
420         for( int i=0; i<that->size(); ++i )
421                 append(new BinFolder(*that->get(i)));
422 }
423
424
425 BinFolderFilter::BinFolderFilter()
426 {
427         enabled = 0;
428         target = 0;
429         op = 0;
430         value = 0;
431 }
432 BinFolderFilter::~BinFolderFilter()
433 {
434         delete enabled;
435         delete target;
436         delete op;
437         delete value;
438 }
439
440 void BinFolderFilter::update_enabled(int type)
441 {
442         if( !enabled )
443                 enabled = new BinFolderEnabled(this, type);
444         else
445                 enabled->update(type);
446 }
447
448 void BinFolderFilter::update_target(int type)
449 {
450         if( target ) {
451                 if( target->type == type ) return;
452                 delete target;  target = 0;
453         }
454         switch( type ) {
455         case FOLDER_TARGET_PATTERNS:    target = new BinFolderTargetPatterns(this);    break;
456         case FOLDER_TARGET_FILE_SIZE:   target = new BinFolderTargetFileSize(this);    break;
457         case FOLDER_TARGET_MOD_TIME:    target = new BinFolderTargetTime(this);        break;
458         case FOLDER_TARGET_TRACK_TYPE:  target = new BinFolderTargetTrackType(this);   break;
459         case FOLDER_TARGET_WIDTH:       target = new BinFolderTargetWidth(this);       break;
460         case FOLDER_TARGET_HEIGHT:      target = new BinFolderTargetHeight(this);      break;
461         case FOLDER_TARGET_FRAMERATE:   target = new BinFolderTargetFramerate(this);   break;
462         case FOLDER_TARGET_SAMPLERATE:  target = new BinFolderTargetSamplerate(this);  break;
463         case FOLDER_TARGET_CHANNELS:    target = new BinFolderTargetChannels(this);    break;
464         case FOLDER_TARGET_DURATION:    target = new BinFolderTargetDuration(this);    break;
465         }
466 }
467
468 void BinFolderFilter::update_op(int type)
469 {
470         if( op ) {
471                 if( op->type == type ) return;
472                 delete op;  op = 0;
473         }
474         switch( type ) {
475         case FOLDER_OP_AROUND:  op = new BinFolderOpAround(this);  break;
476         case FOLDER_OP_EQ:      op = new BinFolderOpEQ(this);      break;
477         case FOLDER_OP_GE:      op = new BinFolderOpGE(this);      break;
478         case FOLDER_OP_GT:      op = new BinFolderOpGT(this);      break;
479         case FOLDER_OP_NE:      op = new BinFolderOpNE(this);      break;
480         case FOLDER_OP_LE:      op = new BinFolderOpLE(this);      break;
481         case FOLDER_OP_LT:      op = new BinFolderOpLT(this);      break;
482         case FOLDER_OP_MATCHES: op = new BinFolderOpMatches(this); break;
483         }
484 }
485
486 void BinFolderFilter::update_value(const char *text)
487 {
488         if( !value )
489                 value = new BinFolderValue(this, text);
490         else
491                 value->update(text);
492 }
493
494 void BinFolderFilter::save_xml(FileXML *file)
495 {
496         file->tag.set_title("FILTER");
497         file->tag.set_property("ENABLED", enabled->type);
498         file->tag.set_property("OP", op->type);
499         file->tag.set_property("TARGET", target->type);
500         target->save_xml(file);
501         file->append_tag();
502         if( target->type == FOLDER_TARGET_PATTERNS )
503                 file->append_text(((BinFolderTargetPatterns *)target)->text);
504         file->tag.set_title("/FILTER");
505         file->append_tag();
506         file->append_newline();
507 }
508
509 int BinFolderFilter::load_xml(FileXML *file)
510 {
511         int enabled_type = file->tag.get_property("ENABLED", FOLDER_ENABLED_AND);
512         int op_type = file->tag.get_property("OP", FOLDER_OP_MATCHES);
513         int target_type = file->tag.get_property("TARGET", FOLDER_TARGET_PATTERNS);
514         char data[0x40000];
515         file->read_text_until("/FILTER", data, sizeof(data), 0);
516         update_enabled(enabled_type);
517         update_target(target_type);
518         update_op(op_type);
519         target->load_xml(file);
520         if( target->type == FOLDER_TARGET_PATTERNS )
521                 ((BinFolderTargetPatterns *)target)->update(data);
522         return 0;
523 }
524
525 void BinFolderFilters::copy_from(BinFolderFilters *that)
526 {
527         clear();
528         for( int i=0; i<that->size(); ++i ) {
529                 BinFolderFilter *filter = new BinFolderFilter();
530                 BinFolderFilter *tp = that->get(i);
531                 filter->update_enabled(tp->enabled->type);
532                 filter->update_target(tp->target->type);
533                 filter->update_op(tp->op->type);
534                 filter->target->copy_from(tp->target);
535                 filter->op->copy_from(tp->op);
536                 append(filter);
537         }
538 }
539
540 double BinFolderOp::around(double v, double a)
541 {
542         if( type != FOLDER_OP_AROUND || a <= 0 ) return v;
543         if( (v=fabs(v)) > a ) return -1;
544         return v / a;
545 }
546
547 // string theory: Feynman, Einstein and Schrodinger string compare
548 //   Feynman: try all possible matches, weight the outcomes
549 //   Schrodinger: it may be there several ways at the same time
550 //   Einstein: the more matches there are, the heavier it is
551 double BinFolderOp::around(const char *ap, const char *bp)
552 {
553         int64_t v = 0, vmx = 0;
554         int alen = strlen(ap), blen = strlen(bp);
555         if( alen > blen ) {
556                 const char *cp = ap;  ap = bp;  bp = cp;
557                 int clen = alen;  alen = blen;  blen = clen;
558         }
559 // 4 level loop (with strncmp), don't try long strings
560         for( int n=0; ++n<=alen; ) {
561                 int64_t nn = n*n;
562                 int an = alen-n+1, bn = blen-n+1;
563                 for( int i=an; --i>=0; ) {
564                         for( int j=bn; --j>=0; ) {
565                                 if( !strncmp(ap+i, bp+j, n) ) v += nn;
566                         }
567                 }
568                 vmx += an*bn*nn;
569         }
570         return !vmx ? -1 : 1 - v / (double)vmx;
571 }
572
573
574 double BinFolderOp::compare(BinFolderTarget *target, Indexable *idxbl)
575 {
576         double v = -1;
577         switch( target->type ) {
578         case FOLDER_TARGET_PATTERNS: {
579                 BinFolderTargetPatterns *tgt = (BinFolderTargetPatterns *)target;
580                 switch( type ) {
581                 case FOLDER_OP_AROUND: {
582                         const char *cp = idxbl->path;
583                         const char *bp = strrchr(cp, '/');
584                         if( bp ) cp = bp + 1;
585                         v = around(cp, tgt->text);
586                         break; }
587                 case FOLDER_OP_EQ:  case FOLDER_OP_GT:  case FOLDER_OP_GE:
588                 case FOLDER_OP_NE:  case FOLDER_OP_LT:  case FOLDER_OP_LE: {
589                         const char *cp = idxbl->path;
590                         const char *bp = strrchr(cp, '/');
591                         if( bp ) cp = bp + 1;
592                         v = strcmp(cp, tgt->text);
593                         break; }
594                 case FOLDER_OP_MATCHES: {
595                         v = -1;
596                         char *cp = tgt->text;
597                         while( v < 0 && *cp ) {
598                                 char pattern[BCTEXTLEN], *bp = pattern, ch;
599                                 while( *cp && (ch=*cp++)!='\n' ) *bp++ = ch;
600                                 *bp = 0;
601                                 if( !pattern[0] ) continue;
602                                 const char *title = idxbl->get_title();
603                                 if( !FileSystem::test_filter(title, pattern) )
604                                         v = 1;
605                         }
606                         break; }
607                 }
608                 break; }
609         case FOLDER_TARGET_FILE_SIZE: {
610                 BinFolderTargetFileSize *tgt = (BinFolderTargetFileSize *)target;
611                 int64_t file_size = !idxbl->is_asset ? -1 :
612                         FileSystem::get_size(idxbl->path);
613                 v = around(file_size - tgt->file_size, tgt->around);
614                 break; }
615         case FOLDER_TARGET_MOD_TIME: {
616                 BinFolderTargetTime *tgt = (BinFolderTargetTime *)target;
617                 struct stat st;
618                 if( stat(idxbl->path, &st) ) break;
619                 v = around(st.st_mtime - tgt->mtime, tgt->around);
620                 break; }
621         case FOLDER_TARGET_TRACK_TYPE: {
622                 BinFolderTargetTrackType *tgt = (BinFolderTargetTrackType *)target;
623                 int want_audio = (tgt->data_types&(1<<TRACK_AUDIO)) ? 1 : 0;
624                 int has_audio = idxbl->have_audio();
625                 if( want_audio != has_audio ) break;
626                 int want_video = (tgt->data_types&(1<<TRACK_VIDEO)) ? 1 : 0;
627                 int has_video = idxbl->have_video();
628                 if( want_video != has_video ) break;
629                 v = 1;
630                 break; }
631         case FOLDER_TARGET_WIDTH: {
632                 BinFolderTargetWidth *tgt = (BinFolderTargetWidth *)target;
633                 int w = idxbl->get_w();
634                 v = around(w - tgt->width, tgt->around);
635                 break; }
636         case FOLDER_TARGET_HEIGHT: {
637                 BinFolderTargetHeight *tgt = (BinFolderTargetHeight *)target;
638                 int h = idxbl->get_h();
639                 v = around(h - tgt->height, tgt->around);
640                 break; }
641         case FOLDER_TARGET_FRAMERATE: {
642                 BinFolderTargetFramerate *tgt = (BinFolderTargetFramerate *)target;
643                 double rate = idxbl->get_frame_rate();
644                 v = around(rate - tgt->framerate, tgt->around);
645                 break; }
646         case FOLDER_TARGET_SAMPLERATE: {
647                 BinFolderTargetSamplerate *tgt = (BinFolderTargetSamplerate *)target;
648                 double rate = idxbl->get_sample_rate();
649                 v = around(rate - tgt->samplerate, tgt->around);
650                 break; }
651         case FOLDER_TARGET_CHANNELS: {
652                 BinFolderTargetChannels *tgt = (BinFolderTargetChannels *)target;
653                 double chs = idxbl->get_audio_channels();
654                 v = around(chs - tgt->channels, tgt->around);
655                 break; }
656         case FOLDER_TARGET_DURATION: {
657                 BinFolderTargetDuration *tgt = (BinFolderTargetDuration *)target;
658                 double len = 0;
659                 double video_rate = !idxbl->have_video() ? 0 : idxbl->get_frame_rate();
660                 if( video_rate > 0 ) {
661                         double video_length = idxbl->get_video_frames() / video_rate;
662                         if( video_length > len ) len = video_length;
663                 }
664                 double audio_rate = !idxbl->have_audio() ? 0 : idxbl->get_sample_rate();
665                 if( audio_rate > 0 ) {
666                         double audio_length = idxbl->get_audio_samples() / audio_rate;
667                         if( audio_length > len ) len = audio_length;
668                 }
669                 v = around(len - tgt->duration, tgt->around);
670                 break; }
671         }
672
673         return v;
674 }
675
676 BinFolderEnabled::BinFolderEnabled(BinFolderFilter *filter, int type)
677  : BC_ListBoxItem(_(types[type]))
678 {
679         this->filter = filter;
680         this->type = type;
681 }
682
683 BinFolderEnabled::~BinFolderEnabled()
684 {
685 }
686
687 void BinFolderEnabled::update(int type)
688 {
689         this->type = type;
690         set_text(_(types[type]));
691 }
692
693 BinFolderEnabledType::BinFolderEnabledType(int no)
694  : BC_MenuItem(_(BinFolderEnabled::types[no]))
695 {
696         this->no = no;
697 }
698 BinFolderEnabledType::~BinFolderEnabledType()
699 {
700 }
701
702 int BinFolderEnabledType::handle_event()
703 {
704         BinFolderEnabledPopup *enabled_popup = (BinFolderEnabledPopup *)get_popup_menu();
705         BinFolderList *folder_list = enabled_popup->folder_list;
706         int i = folder_list->get_selection_number(FOLDER_COLUMN_ENABLE, 0);
707         if( i >= 0 ) {
708                 BinFolder *folder = folder_list->folder;
709                 BinFolderFilter *filter = folder->filters[i];
710                 filter->update_enabled(no);
711                 folder_list->create_list();
712         }
713         return 1;
714 }
715
716 BinFolderEnabledPopup::BinFolderEnabledPopup(BinFolderList *folder_list)
717  : BC_PopupMenu(0, 0, 0, "", 0)
718 {
719         this->folder_list = folder_list;
720         enabled = 0;
721 }
722
723 void BinFolderEnabledPopup::create_objects()
724 {
725         add_item(new BinFolderEnabledType(FOLDER_ENABLED_OFF));
726         add_item(new BinFolderEnabledType(FOLDER_ENABLED_AND));
727         add_item(new BinFolderEnabledType(FOLDER_ENABLED_OR));
728         add_item(new BinFolderEnabledType(FOLDER_ENABLED_AND_NOT));
729         add_item(new BinFolderEnabledType(FOLDER_ENABLED_OR_NOT));
730 }
731
732 void BinFolderEnabledPopup::activate_menu(BC_ListBoxItem *item)
733 {
734         this->enabled = (BinFolderEnabled *)item;
735         BC_PopupMenu::activate_menu();
736 }
737
738 BinFolderTarget::BinFolderTarget(BinFolderFilter *filter, int type)
739  : BC_ListBoxItem(_(types[type]))
740 {
741         this->filter = filter;
742         this->type = type;
743         around = -1;
744 }
745
746 BinFolderTarget::~BinFolderTarget()
747 {
748 }
749
750 BC_Window *BinFolderTarget::new_gui(ModifyTargetThread *thread)
751 {
752         ModifyTargetGUI *window = new ModifyTargetGUI(thread);
753         window->create_objects();
754         return window;
755 }
756
757 BinFolderTargetType::BinFolderTargetType(int no)
758  : BC_MenuItem(_(BinFolderTarget::types[no]))
759 {
760         this->no = no;
761 }
762 BinFolderTargetType::~BinFolderTargetType()
763 {
764 }
765
766 int BinFolderTargetType::handle_event()
767 {
768         BinFolderTargetPopup *target_popup = (BinFolderTargetPopup *)get_popup_menu();
769         BinFolderList *folder_list = target_popup->folder_list;
770         int i = folder_list->get_selection_number(FOLDER_COLUMN_TARGET, 0);
771         if( i >= 0 ) {
772                 BinFolder *folder = folder_list->folder;
773                 BinFolderFilter *filter = folder->filters[i];
774                 filter->update_target(no);
775                 folder_list->create_list();
776         }
777         return 1;
778 }
779
780 BinFolderTargetPopup::BinFolderTargetPopup(BinFolderList *folder_list)
781  : BC_PopupMenu(0, 0, 0, "", 0)
782 {
783         this->folder_list = folder_list;
784         target = 0;
785 }
786
787 void BinFolderTargetPopup::create_objects()
788 {
789         add_item(new BinFolderTargetType(FOLDER_TARGET_PATTERNS));
790         add_item(new BinFolderTargetType(FOLDER_TARGET_FILE_SIZE));
791         add_item(new BinFolderTargetType(FOLDER_TARGET_MOD_TIME));
792         add_item(new BinFolderTargetType(FOLDER_TARGET_TRACK_TYPE));
793         add_item(new BinFolderTargetType(FOLDER_TARGET_WIDTH));
794         add_item(new BinFolderTargetType(FOLDER_TARGET_HEIGHT));
795         add_item(new BinFolderTargetType(FOLDER_TARGET_FRAMERATE));
796         add_item(new BinFolderTargetType(FOLDER_TARGET_SAMPLERATE));
797         add_item(new BinFolderTargetType(FOLDER_TARGET_CHANNELS));
798         add_item(new BinFolderTargetType(FOLDER_TARGET_DURATION));
799 }
800
801 void BinFolderTargetPopup::activate_menu(BC_ListBoxItem *item)
802 {
803         this->target = (BinFolderTarget *)item;
804         BC_PopupMenu::activate_menu();
805 }
806
807
808 BinFolderTargetPatterns::BinFolderTargetPatterns(BinFolderFilter *filter)
809  : BinFolderTarget(filter, FOLDER_TARGET_PATTERNS)
810 {
811         text = 0;
812         update("*");
813 }
814 BinFolderTargetPatterns::~BinFolderTargetPatterns()
815 {
816         delete [] text;
817 }
818  
819 void BinFolderTargetPatterns::save_xml(FileXML *file) {}
820 void BinFolderTargetPatterns::load_xml(FileXML *file) {}
821
822 void BinFolderTargetPatterns::copy_from(BinFolderTarget *that)
823 {
824         BinFolderTargetPatterns *tp = (BinFolderTargetPatterns*)that;
825         update(tp->text);
826 }
827
828 void BinFolderTargetPatterns::update(const char *text)
829 {
830         delete [] this->text;
831         this->text = cstrdup(text);
832         filter->update_value(text);
833 }
834
835 BC_Window *BinFolderTargetPatterns::new_gui(ModifyTargetThread *thread)
836 {
837         return new ModifyTargetPatternsGUI(thread);
838 }
839
840
841 BinFolderTargetFileSize::BinFolderTargetFileSize(BinFolderFilter *filter)
842  : BinFolderTarget(filter, FOLDER_TARGET_FILE_SIZE)
843 {
844         file_size = 0;
845         update(file_size, -1);
846 }
847 BinFolderTargetFileSize::~BinFolderTargetFileSize()
848 {
849 }
850
851 void BinFolderTargetFileSize::save_xml(FileXML *file)
852 {
853         file->tag.set_property("FILE_SIZE", file_size);
854         file->tag.set_property("AROUND", around);
855 }
856
857 void BinFolderTargetFileSize::load_xml(FileXML *file)
858 {
859         int64_t file_size = file->tag.get_property("FILE_SIZE", this->file_size);
860         double around = file->tag.get_property("AROUND", this->around);
861         update(file_size, around);
862 }
863
864 void BinFolderTargetFileSize::copy_from(BinFolderTarget *that)
865 {
866         BinFolderTargetFileSize *tp = (BinFolderTargetFileSize *)that;
867         update(tp->file_size, tp->around);
868 }
869
870 void BinFolderTargetFileSize::update(int64_t file_size, double around)
871 {
872         this->file_size = file_size;
873         this->around = around;
874         char txt[BCSTRLEN], *cp = txt, *ep = cp + sizeof(txt)-1;
875         show_no(file_size, cp, ep);
876         if( around >= 0 && filter->op->type == FOLDER_OP_AROUND ) {
877                 if( cp < ep ) *cp++ = '+';
878                 show_no(around, cp, ep);
879         }
880         *cp = 0;
881         filter->update_value(txt);
882 }
883
884 BC_Window *BinFolderTargetFileSize::new_gui(ModifyTargetThread *thread)
885 {
886         return new ModifyTargetFileSizeGUI(thread);
887 }
888
889
890 BinFolderTargetTime::BinFolderTargetTime(BinFolderFilter *filter)
891  : BinFolderTarget(filter, FOLDER_TARGET_MOD_TIME)
892 {
893         time_t t;  time(&t);
894         mtime = (int64_t)t;
895         update(mtime, -1);
896 }
897 BinFolderTargetTime::~BinFolderTargetTime()
898 {
899 }
900
901 void BinFolderTargetTime::save_xml(FileXML *file)
902 {
903         file->tag.set_property("MTIME", mtime);
904         file->tag.set_property("AROUND", around);
905 }
906
907 void BinFolderTargetTime::load_xml(FileXML *file)
908 {
909         int64_t mtime = file->tag.get_property("MTIME", this->mtime);
910         double around = file->tag.get_property("AROUND", this->around);
911         update(mtime, around);
912 }
913
914 void BinFolderTargetTime::copy_from(BinFolderTarget *that)
915 {
916         BinFolderTargetTime *tp = (BinFolderTargetTime *)that;
917         update(tp->mtime, tp->around);
918 }
919
920 void BinFolderTargetTime::update(int64_t mtime, double around)
921 {
922         this->mtime = mtime;
923         this->around = around;
924         char txt[BCSTRLEN], *cp = txt, *ep = cp + sizeof(txt)-1;
925         show_date(mtime, cp, ep);
926         if( around >= 0 && filter->op->type == FOLDER_OP_AROUND ) {
927                 if( cp < ep ) *cp++ = '+';
928                 show_duration(around, cp, ep);
929         }
930         *cp = 0;
931         filter->update_value(txt);
932 }
933
934 BC_Window *BinFolderTargetTime::new_gui(ModifyTargetThread *thread)
935 {
936         return new ModifyTargetTimeGUI(thread);
937 }
938
939
940 BinFolderTargetTrackType::BinFolderTargetTrackType(BinFolderFilter *filter)
941  : BinFolderTarget(filter, FOLDER_TARGET_TRACK_TYPE)
942 {
943         data_types = (1<<TRACK_AUDIO);
944         update(data_types);
945 }
946 BinFolderTargetTrackType::~BinFolderTargetTrackType()
947 {
948 }
949
950 void BinFolderTargetTrackType::save_xml(FileXML *file)
951 {
952         file->tag.set_property("DATA_TYPES", data_types);
953 }
954
955 void BinFolderTargetTrackType::load_xml(FileXML *file)
956 {
957         int data_types = file->tag.get_property("DATA_TYPES", this->data_types);
958         update(data_types);
959 }
960
961 void BinFolderTargetTrackType::copy_from(BinFolderTarget *that)
962 {
963         BinFolderTargetTrackType *tp = (BinFolderTargetTrackType *)that;
964         update(tp->data_types);
965 }
966
967 void BinFolderTargetTrackType::update(int data_types)
968 {
969         this->data_types = data_types;
970         this->around = -1;
971         char txt[BCSTRLEN], *cp = txt, *ep = cp + sizeof(txt)-1;
972         if( data_types & (1<<TRACK_AUDIO) ) {
973                 if( cp > txt && cp < ep ) *cp++ = ' ';
974                 cp += snprintf(cp, ep-cp, "%s",_("audio"));
975         }
976         if( data_types & (1<<TRACK_VIDEO) ) {
977                 if( cp > txt && cp < ep ) *cp++ = ' ';
978                 cp += snprintf(cp, ep-cp, "%s",_("video"));
979         }
980         *cp = 0;
981         filter->update_value(txt);
982 }
983
984 BC_Window *BinFolderTargetTrackType::new_gui(ModifyTargetThread *thread)
985 {
986         return new ModifyTargetTrackTypeGUI(thread);
987 }
988
989
990 BinFolderTargetWidth::BinFolderTargetWidth(BinFolderFilter *filter)
991  : BinFolderTarget(filter, FOLDER_TARGET_WIDTH)
992 {
993         width = 0;
994         update(width, -1);
995 }
996 BinFolderTargetWidth::~BinFolderTargetWidth()
997 {
998 }
999
1000 void BinFolderTargetWidth::save_xml(FileXML *file)
1001 {
1002         file->tag.set_property("WIDTH", width);
1003         file->tag.set_property("AROUND", around);
1004 }
1005 void BinFolderTargetWidth::load_xml(FileXML *file)
1006 {
1007         int width = file->tag.get_property("WIDTH", this->width);
1008         double around = file->tag.get_property("AROUND", this->around);
1009         update(width, around);
1010 }
1011
1012 void BinFolderTargetWidth::copy_from(BinFolderTarget *that)
1013 {
1014         BinFolderTargetWidth *tp = (BinFolderTargetWidth *)that;
1015         update(tp->width, tp->around);
1016 }
1017
1018 void BinFolderTargetWidth::update(int width, double around)
1019 {
1020         this->width = width;
1021         this->around = around;
1022         char txt[BCSTRLEN], *cp = txt, *ep = cp + sizeof(txt)-1;
1023         show_no(width, cp, ep);
1024         if( around >= 0 && filter->op->type == FOLDER_OP_AROUND ) {
1025                 if( cp < ep ) *cp++ = '+';
1026                 show_no(around, cp, ep);
1027         }
1028         *cp = 0;
1029         filter->update_value(txt);
1030 }
1031
1032 BC_Window *BinFolderTargetWidth::new_gui(ModifyTargetThread *thread)
1033 {
1034         return new ModifyTargetWidthGUI(thread);
1035 }
1036
1037
1038 BinFolderTargetHeight::BinFolderTargetHeight(BinFolderFilter *filter)
1039  : BinFolderTarget(filter, FOLDER_TARGET_HEIGHT)
1040 {
1041         height = 0;
1042         update(height, -1);
1043 }
1044 BinFolderTargetHeight::~BinFolderTargetHeight()
1045 {
1046 }
1047
1048 void BinFolderTargetHeight::save_xml(FileXML *file)
1049 {
1050         file->tag.set_property("HEIGHT", height);
1051         file->tag.set_property("AROUND", around);
1052 }
1053 void BinFolderTargetHeight::load_xml(FileXML *file)
1054 {
1055         int height = file->tag.get_property("HEIGHT", this->height);
1056         double around = file->tag.get_property("AROUND", this->around);
1057         update(height, around);
1058 }
1059
1060 void BinFolderTargetHeight::copy_from(BinFolderTarget *that)
1061 {
1062         BinFolderTargetHeight *tp = (BinFolderTargetHeight *)that;
1063         update(tp->height, tp->around);
1064 }
1065
1066 void BinFolderTargetHeight::update(int height, double around)
1067 {
1068         this->height = height;
1069         this->around = around;
1070         char txt[BCSTRLEN], *cp = txt, *ep = cp + sizeof(txt)-1;
1071         show_no(height, cp, ep);
1072         if( around >= 0 && filter->op->type == FOLDER_OP_AROUND ) {
1073                 if( cp < ep ) *cp++ = '+';
1074                 show_no(around, cp, ep);
1075         }
1076         *cp = 0;
1077         filter->update_value(txt);
1078 }
1079
1080 BC_Window *BinFolderTargetHeight::new_gui(ModifyTargetThread *thread)
1081 {
1082         return new ModifyTargetHeightGUI(thread);
1083 }
1084
1085
1086 BinFolderTargetFramerate::BinFolderTargetFramerate(BinFolderFilter *filter)
1087  : BinFolderTarget(filter, FOLDER_TARGET_FRAMERATE)
1088 {
1089         framerate = 0;
1090         update(framerate, -1);
1091 }
1092 BinFolderTargetFramerate::~BinFolderTargetFramerate()
1093 {
1094 }
1095
1096 void BinFolderTargetFramerate::save_xml(FileXML *file)
1097 {
1098         file->tag.set_property("FRAMERATE", framerate);
1099         file->tag.set_property("AROUND", around);
1100 }
1101
1102 void BinFolderTargetFramerate::load_xml(FileXML *file)
1103 {
1104         double framerate = file->tag.get_property("FRAMERATE", this->framerate);
1105         double around = file->tag.get_property("AROUND", this->around);
1106         update(framerate, around);
1107 }
1108
1109 void BinFolderTargetFramerate::copy_from(BinFolderTarget *that)
1110 {
1111         BinFolderTargetFramerate *tp = (BinFolderTargetFramerate *)that;
1112         update(tp->framerate, tp->around);
1113 }
1114
1115 void BinFolderTargetFramerate::update(double framerate, double around)
1116 {
1117         this->framerate = framerate;
1118         this->around = around;
1119         char txt[BCSTRLEN], *cp = txt, *ep = cp + sizeof(txt)-1;
1120         show_no(framerate, cp, ep, "%0.3f");
1121         if( around >= 0 && filter->op->type == FOLDER_OP_AROUND ) {
1122                 if( cp < ep ) *cp++ = '+';
1123                 show_no(around, cp, ep, "%0.3f");
1124         }
1125         *cp = 0;
1126         filter->update_value(txt);
1127 }
1128
1129 BC_Window *BinFolderTargetFramerate::new_gui(ModifyTargetThread *thread)
1130 {
1131         return new ModifyTargetFramerateGUI(thread);
1132 }
1133
1134
1135 BinFolderTargetSamplerate::BinFolderTargetSamplerate(BinFolderFilter *filter)
1136  : BinFolderTarget(filter, FOLDER_TARGET_SAMPLERATE)
1137 {
1138         samplerate = 0;
1139         update(samplerate, -1);
1140 }
1141
1142 BinFolderTargetSamplerate::~BinFolderTargetSamplerate()
1143 {
1144 }
1145
1146 void BinFolderTargetSamplerate::save_xml(FileXML *file)
1147 {
1148         file->tag.set_property("SAMPLERATE", samplerate);
1149         file->tag.set_property("AROUND", around);
1150 }
1151
1152 void BinFolderTargetSamplerate::load_xml(FileXML *file)
1153 {
1154         double samplerate = file->tag.get_property("SAMPLERATE", this->samplerate);
1155         double around = file->tag.get_property("AROUND", this->around);
1156         update(samplerate, around);
1157 }
1158
1159 void BinFolderTargetSamplerate::copy_from(BinFolderTarget *that)
1160 {
1161         BinFolderTargetSamplerate *tp = (BinFolderTargetSamplerate *)that;
1162         update(tp->samplerate, tp->around);
1163 }
1164
1165 void BinFolderTargetSamplerate::update(int samplerate, double around)
1166 {
1167         this->samplerate = samplerate;
1168         this->around = around;
1169         char txt[BCSTRLEN], *cp = txt, *ep = cp + sizeof(txt)-1;
1170         show_no(samplerate, cp, ep);
1171         if( around >= 0 && filter->op->type == FOLDER_OP_AROUND ) {
1172                 if( cp < ep ) *cp++ = '+';
1173                 show_no(around, cp, ep);
1174         }
1175         *cp = 0;
1176         filter->update_value(txt);
1177 }
1178
1179 BC_Window *BinFolderTargetSamplerate::new_gui(ModifyTargetThread *thread)
1180 {
1181         return new ModifyTargetSamplerateGUI(thread);
1182 }
1183
1184
1185 BinFolderTargetChannels::BinFolderTargetChannels(BinFolderFilter *filter)
1186  : BinFolderTarget(filter, FOLDER_TARGET_CHANNELS)
1187 {
1188         channels = 0;
1189         update(channels, -1);
1190 }
1191 BinFolderTargetChannels::~BinFolderTargetChannels()
1192 {
1193 }
1194
1195 void BinFolderTargetChannels::save_xml(FileXML *file)
1196 {
1197         file->tag.set_property("CHANNELS", channels);
1198         file->tag.set_property("AROUND", around);
1199 }
1200
1201 void BinFolderTargetChannels::load_xml(FileXML *file)
1202 {
1203         int channels = file->tag.get_property("CHANNELS", this->channels);
1204         double around = file->tag.get_property("AROUND", this->around);
1205         update(channels, around);
1206 }
1207
1208 void BinFolderTargetChannels::copy_from(BinFolderTarget *that)
1209 {
1210         BinFolderTargetChannels *tp = (BinFolderTargetChannels *)that;
1211         update(tp->channels, tp->around);
1212 }
1213
1214 void BinFolderTargetChannels::update(int channels, double around)
1215 {
1216         this->channels = channels;
1217         this->around = around;
1218         char txt[BCSTRLEN], *cp = txt, *ep = cp + sizeof(txt)-1;
1219         show_no(channels, cp, ep);
1220         if( around >= 0 && filter->op->type == FOLDER_OP_AROUND ) {
1221                 if( cp < ep ) *cp++ = '+';
1222                 show_no(around, cp, ep);
1223         }
1224         *cp = 0;
1225         filter->update_value(txt);
1226 }
1227
1228 BC_Window *BinFolderTargetChannels::new_gui(ModifyTargetThread *thread)
1229 {
1230         return new ModifyTargetChannelsGUI(thread);
1231 }
1232
1233
1234 BinFolderTargetDuration::BinFolderTargetDuration(BinFolderFilter *filter)
1235  : BinFolderTarget(filter, FOLDER_TARGET_DURATION)
1236 {
1237         duration = 0;
1238         update(duration, -1);
1239 }
1240 BinFolderTargetDuration::~BinFolderTargetDuration()
1241 {
1242 }
1243
1244 void BinFolderTargetDuration::save_xml(FileXML *file)
1245 {
1246         file->tag.set_property("DURATION", duration);
1247         file->tag.set_property("AROUND", around);
1248 }
1249
1250 void BinFolderTargetDuration::load_xml(FileXML *file)
1251 {
1252         int64_t duration = file->tag.get_property("DURATION", this->duration);
1253         double around = file->tag.get_property("AROUND", this->around);
1254         update(duration, around);
1255 }
1256
1257 void BinFolderTargetDuration::copy_from(BinFolderTarget *that)
1258 {
1259         BinFolderTargetDuration *tp = (BinFolderTargetDuration *)that;
1260         update(tp->duration, tp->around);
1261 }
1262
1263 void BinFolderTargetDuration::update(int64_t duration, double around)
1264 {
1265         this->duration = duration;
1266         this->around = around;
1267         char txt[BCSTRLEN], *cp = txt, *ep = cp + sizeof(txt)-1;
1268         show_duration(duration, cp, ep);
1269         if( around >= 0 && filter->op->type == FOLDER_OP_AROUND ) {
1270                 if( cp < ep ) *cp++ = '+';
1271                 show_duration(around, cp, ep);
1272         }
1273         *cp = 0;
1274         filter->update_value(txt);
1275 }
1276
1277 BC_Window *BinFolderTargetDuration::new_gui(ModifyTargetThread *thread)
1278 {
1279         return new ModifyTargetDurationGUI(thread);
1280 }
1281
1282
1283 BinFolderOp::BinFolderOp(BinFolderFilter *filter, int type)
1284  : BC_ListBoxItem(_(types[type]))
1285 {
1286         this->filter = filter;
1287         this->type = type;
1288 }
1289
1290 BinFolderOp::~BinFolderOp()
1291 {
1292 }
1293
1294 void BinFolderOp::copy_from(BinFolderOp *that)
1295 {
1296         type = that->type;
1297 }
1298
1299 BinFolderOpType::BinFolderOpType(int no)
1300  : BC_MenuItem(_(BinFolderOp::types[no]))
1301 {
1302         this->no = no;
1303 }
1304 BinFolderOpType::~BinFolderOpType()
1305 {
1306 }
1307
1308 int BinFolderOpType::handle_event()
1309 {
1310         BinFolderOpPopup *op_popup = (BinFolderOpPopup *)get_popup_menu();
1311         BinFolderList *folder_list = op_popup->folder_list;
1312         int i = folder_list->get_selection_number(FOLDER_COLUMN_OP, 0);
1313         if( i >= 0 ) {
1314                 BinFolder *folder = folder_list->folder;
1315                 BinFolderFilter *filter = folder->filters[i];
1316                 filter->update_op(no);
1317                 folder_list->create_list();
1318         }
1319         return 1;
1320 }
1321
1322 BinFolderOpPopup::BinFolderOpPopup(BinFolderList *folder_list)
1323  : BC_PopupMenu(0, 0, 0, "", 0)
1324 {
1325         this->folder_list = folder_list;
1326         op = 0;
1327 }
1328
1329 void BinFolderOpPopup::create_objects()
1330 {
1331         add_item(new BinFolderOpType(FOLDER_OP_AROUND));
1332         add_item(new BinFolderOpType(FOLDER_OP_EQ));
1333         add_item(new BinFolderOpType(FOLDER_OP_GE));
1334         add_item(new BinFolderOpType(FOLDER_OP_GT));
1335         add_item(new BinFolderOpType(FOLDER_OP_NE));
1336         add_item(new BinFolderOpType(FOLDER_OP_LE));
1337         add_item(new BinFolderOpType(FOLDER_OP_LT));
1338         add_item(new BinFolderOpType(FOLDER_OP_MATCHES));
1339 }
1340
1341 void BinFolderOpPopup::activate_menu(BC_ListBoxItem *item)
1342 {
1343         this->op = (BinFolderOp *)item;
1344         BC_PopupMenu::activate_menu();
1345 }
1346
1347 double BinFolderOp::test(BinFolderTarget *target, Indexable *idxbl)
1348 {
1349         return -1;
1350 }
1351
1352 double BinFolderOpEQ::test(BinFolderTarget *target, Indexable *idxbl)
1353 {
1354         double v = compare(target, idxbl);
1355         return v == 0 ? 1 : -1;
1356 }
1357
1358 double BinFolderOpGT::test(BinFolderTarget *target, Indexable *idxbl)
1359 {
1360         double v = compare(target, idxbl);
1361         return v > 0 ? 1 : -1;
1362 }
1363
1364 double BinFolderOpGE::test(BinFolderTarget *target, Indexable *idxbl)
1365 {
1366         double v = compare(target, idxbl);
1367         return v >= 0 ? 1 : -1;
1368 }
1369
1370 double BinFolderOpNE::test(BinFolderTarget *target, Indexable *idxbl)
1371 {
1372         double v = compare(target, idxbl);
1373         return v != 0 ? 1 : -1;
1374 }
1375
1376 double BinFolderOpLT::test(BinFolderTarget *target, Indexable *idxbl)
1377 {
1378         double v = compare(target, idxbl);
1379         return v < 0 ? 1 : -1;
1380 }
1381
1382 double BinFolderOpLE::test(BinFolderTarget *target, Indexable *idxbl)
1383 {
1384         double v = compare(target, idxbl);
1385         return v <= 0 ? 1 : -1;
1386 }
1387
1388 double BinFolderOpMatches::test(BinFolderTarget *target, Indexable *idxbl)
1389 {
1390         double v = compare(target, idxbl);
1391         return v;
1392 }
1393
1394 double BinFolderOpAround::test(BinFolderTarget *target, Indexable *idxbl)
1395 {
1396         double v = compare(target, idxbl);
1397         return v;
1398 }
1399
1400 BinFolderValue::BinFolderValue(BinFolderFilter *filter, const char *text)
1401  : BC_ListBoxItem()
1402 {
1403         this->filter = filter;
1404         update(text);
1405 }
1406
1407 BinFolderValue::~BinFolderValue()
1408 {
1409 }
1410
1411
1412 void BinFolderValue::update(const char *text)
1413 {
1414         const char *cp = text;
1415         char txt[BCSTRLEN], *tp = txt;
1416         for( int i=sizeof(txt); --i>0 && *cp!=0 && *cp!='\n'; ++tp,++cp ) *tp = *cp;
1417         *tp = 0;
1418         set_text(txt);
1419 }
1420
1421
1422 BinFolderList::BinFolderList(BinFolder *folder, MWindow *mwindow,
1423                 ModifyFolderGUI *window, int x, int y, int w, int h)
1424  : BC_ListBox(x, y, w, h, LISTBOX_TEXT, 0,
1425         0, 0, 1, 0, 0, LISTBOX_SINGLE, ICON_LEFT, 1)
1426 {
1427         this->folder = folder;
1428         this->mwindow = mwindow;
1429         this->window = window;
1430         dragging_item = 0;
1431         set_process_drag(1);
1432         enabled_popup = 0;
1433         op_popup = 0;
1434         target_popup = 0;
1435         modify_target = 0;
1436 }
1437
1438 BinFolderList::~BinFolderList()
1439 {
1440         save_defaults(mwindow->defaults);
1441         delete modify_target;
1442 }
1443
1444 void BinFolderList::create_objects()
1445 {
1446         list_titles[FOLDER_COLUMN_ENABLE] = _("Enable");
1447         list_titles[FOLDER_COLUMN_TARGET] = _("Target");
1448         list_titles[FOLDER_COLUMN_OP]     = _("Op");
1449         list_titles[FOLDER_COLUMN_VALUE]  = _("Value");
1450         list_width[FOLDER_COLUMN_ENABLE]  = 80;
1451         list_width[FOLDER_COLUMN_TARGET]  = 80;
1452         list_width[FOLDER_COLUMN_OP]      = 50;
1453         list_width[FOLDER_COLUMN_VALUE]   = 180;
1454         load_defaults(mwindow->defaults);
1455         create_list();
1456         add_subwindow(enabled_popup = new BinFolderEnabledPopup(this));
1457         enabled_popup->create_objects();
1458         add_subwindow(op_popup = new BinFolderOpPopup(this));
1459         op_popup->create_objects();
1460         add_subwindow(target_popup = new BinFolderTargetPopup(this));
1461         target_popup->create_objects();
1462
1463         modify_target = new ModifyTargetThread(this);
1464 }
1465
1466 void BinFolderList::create_list()
1467 {
1468         for( int i=0; i<FOLDER_COLUMNS; ++i )
1469                 list_items[i].remove_all();
1470         for( int i=0; i<folder->filters.size(); ++i ) {
1471                 BinFolderFilter *filter = folder->filters[i];
1472                 list_items[FOLDER_COLUMN_ENABLE].append(filter->enabled);
1473                 list_items[FOLDER_COLUMN_TARGET].append(filter->target);
1474                 list_items[FOLDER_COLUMN_OP].append(filter->op);
1475                 list_items[FOLDER_COLUMN_VALUE].append(filter->value);
1476         }
1477         update(list_items, list_titles, list_width, FOLDER_COLUMNS,
1478                 get_xposition(), get_yposition(), get_highlighted_item(),
1479                 1, 1);
1480 }
1481
1482 int BinFolderList::handle_event()
1483 {
1484         return 1;
1485 }
1486
1487 int BinFolderList::selection_changed()
1488 {
1489         if( !cursor_above() ) return 0;
1490         int no = get_selection_number(0, 0);
1491         if( no < 0 ) return 0;
1492         BinFolderFilter *filter = folder->filters[no];
1493         if( get_button_down() && get_buttonpress() == 3 ) {
1494                 int cx = get_cursor_x(), col = -1;
1495                 for( int i=0; col<0 && i<FOLDER_COLUMNS; ++i ) {
1496                         int ofs = get_column_offset(i);
1497                         if( cx >= ofs && cx < ofs+get_column_width(i) ) {
1498                                 col = i;  break;
1499                         }
1500                 }
1501                 BC_ListBoxItem *item = col >= 0 ? get_selection(col, 0) : 0;
1502                 if( item ) {
1503                         deactivate_selection();
1504                         switch( col ) {
1505                         case FOLDER_COLUMN_ENABLE:
1506                                 enabled_popup->activate_menu(item);
1507                                 break;
1508                         case FOLDER_COLUMN_TARGET:
1509                                 target_popup->activate_menu(item);
1510                                 break;
1511                         case FOLDER_COLUMN_OP:
1512                                 op_popup->activate_menu(item);
1513                                 break;
1514                         case FOLDER_COLUMN_VALUE: {
1515                                 modify_target->close_window();
1516                                 int cw = filter->target->type == FOLDER_TARGET_PATTERNS ? 400 : 320;
1517                                 int ch = filter->target->type == FOLDER_TARGET_PATTERNS ? 300 : 120;
1518                                 int cx, cy;  get_abs_cursor(cx, cy);
1519                                 if( (cx-=cw/2) < 50 ) cx = 50;
1520                                 if( (cy-=ch/2) < 50 ) cy = 50;
1521                                 modify_target->start(filter->target, cx, cy, cw, ch);
1522                                 break; }
1523                         }
1524                 }
1525         }
1526         return 1;
1527 }
1528
1529 int BinFolderList::column_resize_event()
1530 {
1531         for( int i = 0; i < FOLDER_COLUMNS; i++ ) {
1532                 list_width[i] = get_column_width(i);
1533         }
1534         return 1;
1535 }
1536
1537 int BinFolderList::drag_start_event()
1538 {
1539         if( BC_ListBox::drag_start_event() ) {
1540                 dragging_item = 1;
1541                 return 1;
1542         }
1543
1544         return 0;
1545 }
1546
1547 int BinFolderList::drag_motion_event()
1548 {
1549         if( BC_ListBox::drag_motion_event() ) {
1550                 return 1;
1551         }
1552         return 0;
1553 }
1554
1555 int BinFolderList::drag_stop_event()
1556 {
1557         if( dragging_item ) {
1558                 int src = get_selection_number(0, 0);
1559                 int dst = get_highlighted_item();
1560                 if( src != dst ) {
1561                         move_filter(src, dst);
1562                 }
1563                 BC_ListBox::drag_stop_event();
1564                 dragging_item = 0;
1565         }
1566         return 0;
1567 }
1568
1569 void BinFolderList::move_filter(int src, int dst)
1570 {
1571         BinFolderFilters &filters = folder->filters;
1572         BinFolderFilter *src_filter = filters[src];
1573         if( dst < 0 ) dst = filters.size()-1;
1574
1575         if( dst != src ) {
1576                 for( int i=src; i<filters.size()-1; ++i )
1577                         filters[i] = filters[i+1];
1578                 for( int i=filters.size(); --i>dst; )
1579                         filters[i] = filters[i-1];
1580                 filters[dst] = src_filter;
1581         }
1582 }
1583
1584 void BinFolderList::save_defaults(BC_Hash *defaults)
1585 {
1586         defaults->update("BIN_FOLDER_ENA", list_width[FOLDER_COLUMN_ENABLE]);
1587         defaults->update("BIN_FOLDER_TGT", list_width[FOLDER_COLUMN_TARGET]);
1588         defaults->update("BIN_FOLDER_OPR", list_width[FOLDER_COLUMN_OP]);
1589         defaults->update("BIN_FOLDER_VAL", list_width[FOLDER_COLUMN_VALUE]);
1590 }
1591 void BinFolderList::load_defaults(BC_Hash *defaults)
1592 {
1593         list_width[FOLDER_COLUMN_ENABLE] = defaults->get("BIN_FOLDER_ENA", list_width[FOLDER_COLUMN_ENABLE]);
1594         list_width[FOLDER_COLUMN_TARGET] = defaults->get("BIN_FOLDER_TGT", list_width[FOLDER_COLUMN_TARGET]);
1595         list_width[FOLDER_COLUMN_OP]     = defaults->get("BIN_FOLDER_OPR", list_width[FOLDER_COLUMN_OP]);
1596         list_width[FOLDER_COLUMN_VALUE]  = defaults->get("BIN_FOLDER_VAL", list_width[FOLDER_COLUMN_VALUE]);
1597 }
1598
1599 BinFolderAddFilter::BinFolderAddFilter(BinFolderList *folder_list, int x, int y)
1600  : BC_GenericButton(x, y, _("Add"))
1601 {
1602         this->folder_list = folder_list;
1603 }
1604 BinFolderAddFilter::~BinFolderAddFilter()
1605 {
1606 }
1607
1608 int BinFolderAddFilter::handle_event()
1609 {
1610         folder_list->modify_target->close_window();
1611 // default new filter
1612         BinFolderFilter *filter = new BinFolderFilter();
1613         filter->update_enabled(FOLDER_ENABLED_OR);
1614         filter->update_target(FOLDER_TARGET_PATTERNS);
1615         filter->update_op(FOLDER_OP_MATCHES);
1616         BinFolderTargetPatterns *patterns = (BinFolderTargetPatterns *)(filter->target);
1617         filter->update_value(patterns->text);
1618         folder_list->folder->filters.append(filter);
1619         folder_list->create_list();
1620         return 1;
1621 }
1622
1623 BinFolderDelFilter::BinFolderDelFilter(BinFolderList *folder_list, int x, int y)
1624  : BC_GenericButton(x, y, _("Del"))
1625 {
1626         this->folder_list = folder_list;
1627 }
1628 BinFolderDelFilter::~BinFolderDelFilter()
1629 {
1630 }
1631
1632 int BinFolderDelFilter::handle_event()
1633 {
1634         folder_list->modify_target->close_window();
1635         int no = folder_list->get_selection_number(0, 0);
1636         if( no >= 0 ) {
1637                 folder_list->folder->filters.remove_object_number(no);
1638                 folder_list->create_list();
1639         }
1640         return 1;
1641 }
1642
1643 BinFolderApplyFilter::BinFolderApplyFilter(BinFolderList *folder_list, int x, int y)
1644  : BC_GenericButton(x, y, _("Apply"))
1645 {
1646         this->folder_list = folder_list;
1647 }
1648 BinFolderApplyFilter::~BinFolderApplyFilter()
1649 {
1650 }
1651
1652 int BinFolderApplyFilter::handle_event()
1653 {
1654         ModifyFolderThread *thread = folder_list->window->thread;
1655         thread->original->copy_from(thread->folder);
1656         thread->agui->async_update_assets();
1657         return 1;
1658 }
1659
1660
1661 NewFolderGUI::NewFolderGUI(NewFolderThread *thread, int x, int y, int w, int h)
1662  : BC_Window(_(PROGRAM_NAME ": New folder"),
1663                 x, y, w, h, -1, -1, 0, 0, 1)
1664 {
1665         this->thread = thread;
1666 }
1667
1668 NewFolderGUI::~NewFolderGUI()
1669 {
1670 }
1671
1672 void NewFolderGUI::create_objects()
1673 {
1674         lock_window("NewFolderGUI::create_objects");
1675         int x = 10, y = 10;
1676         BC_Title *title;
1677         add_subwindow(title = new BC_Title(x, y, _("Folder name:")));
1678         y += title->get_h() + 5;
1679         const char *text = !thread->is_clips ? _("media bin") : _("clip bin");
1680         add_subwindow(text_box = new BC_TextBox(x, y, 300, 1, text));
1681         add_subwindow(new BC_OKButton(this));
1682         add_subwindow(new BC_CancelButton(this));
1683         show_window();
1684         unlock_window();
1685 }
1686
1687 const char* NewFolderGUI::get_text()
1688 {
1689         return text_box->get_text();
1690 }
1691
1692
1693 NewFolderThread::NewFolderThread(AWindowGUI *agui)
1694  : BC_DialogThread()
1695 {
1696         this->agui = agui;
1697         is_clips = -1;
1698 }
1699
1700 NewFolderThread::~NewFolderThread()
1701 {
1702         close_window();
1703 }
1704
1705 void NewFolderThread::start(int x, int y, int w, int h, int is_clips)
1706 {
1707         close_window();
1708         this->is_clips = is_clips;
1709         this->wx = x;  this->wy = y;
1710         this->ww = w;  this->wh = h;
1711         Thread::start();
1712 }
1713
1714 BC_Window *NewFolderThread::new_gui()
1715 {
1716         window = new NewFolderGUI(this, wx, wy, ww, wh);
1717         window->create_objects();
1718         return window;
1719 }
1720
1721 void NewFolderThread::handle_done_event(int result)
1722 {
1723         if( !result ) {
1724                 const char *text = window->get_text();
1725                 agui->mwindow->new_folder(text, is_clips);
1726         }
1727 }
1728
1729 void NewFolderThread::handle_close_event(int result)
1730 {
1731         is_clips = -1;
1732 }
1733
1734 ModifyFolderGUI::ModifyFolderGUI(ModifyFolderThread *thread, int x, int y, int w, int h)
1735  : BC_Window(_(PROGRAM_NAME ": Modify folder"), x, y, w, h, 320, 200, 1, 0, 1)
1736 {
1737         this->thread = thread;
1738 }
1739
1740 ModifyFolderGUI::~ModifyFolderGUI()
1741 {
1742 }
1743
1744 int ModifyFolderGUI::receive_custom_xatoms(xatom_event *event)
1745 {
1746         if( event->message_type == modify_folder_xatom ) {
1747                 update_filters();
1748                 return 1;
1749         }
1750         return 0;
1751 }
1752
1753 void ModifyFolderGUI::async_update_filters()
1754 {
1755         xatom_event event;
1756         event.message_type = modify_folder_xatom;
1757         send_custom_xatom(&event);
1758 }
1759
1760
1761 void ModifyFolderGUI::create_objects()
1762 {
1763         lock_window("ModifyFolderGUI::create_objects");
1764         modify_folder_xatom = create_xatom("CWINDOWGUI_UPDATE_FILTERS");
1765         int x = 10, y = 10;
1766         BC_Title *title;
1767         add_subwindow(title = new BC_Title(x, y, _("Enter the name of the folder:")));
1768         const char *text = !thread->folder->is_clips ? _("Media") : _("Clips");
1769         int tw = BC_Title::calculate_w(this, text, LARGEFONT);
1770         int x0 = get_w() - 50 - tw;
1771         add_subwindow(text_title = new BC_Title(x0, y, text, LARGEFONT, YELLOW));
1772         y += title->get_h() + 10;
1773         add_subwindow(text_box = new BC_TextBox(x, y, 300, 1, thread->folder->title));
1774         y += text_box->get_h() + 10;
1775         int lh = get_h() - y - BC_OKButton::calculate_h() - 30;
1776         int lw = get_w() - x - 120;
1777         add_subwindow(folder_list =
1778                 new BinFolderList(thread->folder, thread->agui->mwindow, this, x, y, lw, lh));
1779         folder_list->create_objects();
1780         int x1 = x + folder_list->get_w() + 15, y1 = y;
1781         add_subwindow(add_filter = new BinFolderAddFilter(folder_list, x1, y1));
1782         y1 += add_filter->get_h() + 10;
1783         add_subwindow(del_filter = new BinFolderDelFilter(folder_list, x1, y1));
1784         y1 += del_filter->get_h() + 10;
1785         add_subwindow(apply_filter = new BinFolderApplyFilter(folder_list, x1, y1));
1786         add_subwindow(ok_button = new BC_OKButton(this));
1787         add_subwindow(cancel_button = new BC_CancelButton(this));
1788         show_window();
1789         unlock_window();
1790 }
1791
1792 int ModifyFolderGUI::resize_event(int w, int h)
1793 {
1794         MWindow *mwindow = thread->agui->mwindow;
1795         mwindow->session->bwindow_w = w;
1796         mwindow->session->bwindow_h = h;
1797         int tx = text_title->get_x() + w - get_w();
1798         int ty = text_title->get_y();
1799         text_title->reposition_window(tx, ty);
1800         int lx = folder_list->get_x();
1801         int ly = folder_list->get_y();
1802         int lh = h - ly - BC_OKButton::calculate_h() - 30;
1803         int lw = w - lx - 120;
1804         folder_list->reposition_window(lx, ly, lw, lh);
1805         int x1 = lx + lw + 15;
1806         add_filter->reposition_window(x1, add_filter->get_y());
1807         del_filter->reposition_window(x1, del_filter->get_y());
1808         apply_filter->reposition_window(x1,apply_filter->get_y());
1809         ok_button->resize_event(w, h);
1810         cancel_button->resize_event(w, h);
1811         return 1;
1812 }
1813
1814 const char* ModifyFolderGUI::get_text()
1815 {
1816         return text_box->get_text();
1817 }
1818
1819 void ModifyFolderGUI::update_filters()
1820 {
1821         folder_list->create_list();
1822 }
1823
1824
1825 ModifyFolderThread::ModifyFolderThread(AWindowGUI *agui)
1826  : BC_DialogThread()
1827 {
1828         this->agui = agui;
1829         original = 0;
1830         folder = 0;
1831 }
1832
1833 ModifyFolderThread::~ModifyFolderThread()
1834 {
1835         close_window();
1836         delete folder;
1837 }
1838
1839 void ModifyFolderThread::start(BinFolder *folder, int x, int y, int w, int h)
1840 {
1841         close_window();
1842         this->original = folder;
1843         agui->mwindow->edl->add_user();
1844         this->folder = new BinFolder(*folder);
1845         this->wx = x;  this->wy = y;
1846         this->ww = w;  this->wh = h;
1847         Thread::start();
1848 }
1849
1850 BC_Window *ModifyFolderThread::new_gui()
1851 {
1852         window = new ModifyFolderGUI(this, wx, wy, ww, wh);
1853         window->create_objects();
1854         return window;
1855 }
1856
1857 void ModifyFolderThread::handle_done_event(int result)
1858 {
1859         if( !result ) {
1860                 const char *title = window->get_text();
1861                 if( strcmp(folder->title, title) ) {
1862                         if( agui->mwindow->edl->get_folder_number(title) >= 0 ) {
1863                                 eprintf("folder already exists: %s", title);
1864                                 result = 1;
1865                         }
1866                         else
1867                                 strncpy(folder->title, title,sizeof(folder->title));
1868                 }
1869         }
1870         if( !result ) {
1871                 original->copy_from(folder);
1872                 agui->async_update_assets();
1873         }
1874         delete folder;  folder = 0;
1875         original = 0;
1876         agui->mwindow->edl->remove_user();
1877 }
1878
1879 void ModifyFolderThread::handle_close_event(int result)
1880 {
1881 }
1882
1883
1884 ModifyTargetThread::ModifyTargetThread(BinFolderList *folder_list)
1885  : BC_DialogThread()
1886 {
1887         this->folder_list = folder_list;
1888         target = 0;
1889 }
1890
1891 ModifyTargetThread::~ModifyTargetThread()
1892 {
1893         close_window();
1894 }
1895
1896 void ModifyTargetThread::start(BinFolderTarget *target, int x, int y, int w, int h)
1897 {
1898         this->target = target;
1899         wx = x;  wy = y;
1900         ww = w;  wh = h;
1901         Thread::start();
1902 }
1903
1904 BC_Window *ModifyTargetThread::new_gui()
1905 {
1906         window = (ModifyTargetGUI *)target->new_gui(this);
1907         window->create_objects();
1908         return window;
1909 }
1910
1911 void ModifyTargetThread::handle_done_event(int result)
1912 {
1913         if( !result ) {
1914                 window->update();
1915                 folder_list->window->async_update_filters();
1916         }
1917 }
1918
1919 void ModifyTargetThread::handle_close_event(int result)
1920 {
1921         target = 0;
1922 }
1923
1924 ModifyTargetGUI::ModifyTargetGUI(ModifyTargetThread *thread, int allow_resize)
1925  : BC_Window(_(PROGRAM_NAME ": Modify target"),
1926                 thread->wx, thread->wy, thread->ww, thread->wh,
1927                 -1, -1, allow_resize, 0, 1)
1928 {
1929         this->thread = thread;
1930 }
1931
1932 ModifyTargetGUI::~ModifyTargetGUI()
1933 {
1934 }
1935
1936 void ModifyTargetGUI::create_objects(BC_TextBox *&text_box)
1937 {
1938         lock_window("ModifyTargetGUI::create_objects");
1939         int x = 10, y = 10;
1940         const char *text = thread->target->filter->value->get_text();
1941         add_subwindow(text_box = new BC_TextBox(x, y, get_w()-20, 1, text));
1942         add_subwindow(new BC_OKButton(this));
1943         add_subwindow(new BC_CancelButton(this));
1944         show_window();
1945         unlock_window();
1946 }
1947
1948 int ModifyTargetGUI::resize_event(int w, int h)
1949 {
1950         return BC_WindowBase::resize_event(w, h);
1951 }
1952
1953 ModifyTargetPatternsGUI::ModifyTargetPatternsGUI(ModifyTargetThread *thread)
1954  : ModifyTargetGUI(thread, 1)
1955 {
1956         this->thread = thread;
1957         scroll_text_box = 0;
1958         text_rowsz = 0;
1959 }
1960
1961 ModifyTargetPatternsGUI::~ModifyTargetPatternsGUI()
1962 {
1963         delete scroll_text_box;
1964 }
1965
1966 void ModifyTargetPatternsGUI::create_objects()
1967 {
1968         lock_window("ModifyTargetPatternsGUI::create_objects");
1969         BinFolderTargetPatterns *target = (BinFolderTargetPatterns *)thread->target;
1970         int x = 10, y = 10;
1971         int text_font = MEDIUMFONT;
1972         text_rowsz = get_text_ascent(text_font)+1 + get_text_descent(text_font)+1;
1973         int th = get_h() - y - BC_OKButton::calculate_h() - 20;
1974         int rows = th / text_rowsz;
1975         int text_len = strlen(target->text);
1976         if( text_len < BCTEXTLEN ) text_len = BCTEXTLEN;
1977         scroll_text_box = new BC_ScrollTextBox(this, x, y, get_w()-20, rows,
1978                 target->text, 2*text_len);
1979         scroll_text_box->create_objects();
1980         add_subwindow(ok_button = new BC_OKButton(this));
1981         add_subwindow(cancel_button = new BC_CancelButton(this));
1982         show_window();
1983         unlock_window();
1984 }
1985
1986 int ModifyTargetPatternsGUI::resize_event(int w, int h)
1987 {
1988         int tx = scroll_text_box->get_x();
1989         int ty = scroll_text_box->get_y();
1990         int th = h - ty - BC_OKButton::calculate_h() - 20;
1991         int tw = w - 20;
1992         int rows = th / text_rowsz;
1993         scroll_text_box->reposition_window(tx, ty, tw, rows);
1994         ok_button->resize_event(w, h);
1995         cancel_button->resize_event(w, h);
1996         return 1;
1997 }
1998
1999 void ModifyTargetPatternsGUI::update()
2000 {
2001         BinFolderTargetPatterns *target = (BinFolderTargetPatterns *)thread->target;
2002         const char *cp = scroll_text_box->get_text();
2003         target->update(cp);
2004 }
2005
2006
2007 ModifyTargetFileSizeGUI::ModifyTargetFileSizeGUI(ModifyTargetThread *thread)
2008  : ModifyTargetGUI(thread)
2009 {
2010 }
2011
2012 ModifyTargetFileSizeGUI::~ModifyTargetFileSizeGUI()
2013 {
2014 }
2015
2016 void ModifyTargetFileSizeGUI::create_objects()
2017 {
2018         ModifyTargetGUI::create_objects(text_box);
2019 }
2020
2021 void ModifyTargetFileSizeGUI::update()
2022 {
2023         BinFolderTargetFileSize *target = (BinFolderTargetFileSize *)thread->target;
2024         double file_size = target->file_size, around = target->around;
2025         const char *cp = text_box->get_text();  char *bp = 0;
2026         scan_around(cp, bp, file_size, around);
2027         target->update(file_size, around);
2028 }
2029
2030
2031 ModifyTargetTimeGUI::ModifyTargetTimeGUI(ModifyTargetThread *thread)
2032  : ModifyTargetGUI(thread)
2033 {
2034 }
2035
2036 ModifyTargetTimeGUI::~ModifyTargetTimeGUI()
2037 {
2038 }
2039
2040 void ModifyTargetTimeGUI::create_objects()
2041 {
2042         ModifyTargetGUI::create_objects(text_box);
2043 }
2044
2045 void ModifyTargetTimeGUI::update()
2046 {
2047         BinFolderTargetTime *target = (BinFolderTargetTime *)thread->target;
2048         int64_t mtime = target->mtime;  double around = target->around;
2049         const char *cp = text_box->get_text(); char *bp = 0;
2050         int64_t v = scan_date(cp, bp);
2051         if( bp > cp ) {
2052                 mtime = v;
2053                 if( *bp == '+' ) {
2054                         v = scan_duration(cp=bp+1, bp);
2055                         if( bp > cp ) around = v;
2056                 }
2057         }
2058         target->update(mtime, around);
2059 }
2060
2061
2062 ModifyTargetTrackTypeGUI::ModifyTargetTrackTypeGUI(ModifyTargetThread *thread)
2063  : ModifyTargetGUI(thread)
2064 {
2065 }
2066
2067 ModifyTargetTrackTypeGUI::~ModifyTargetTrackTypeGUI()
2068 {
2069 }
2070
2071 void ModifyTargetTrackTypeGUI::create_objects()
2072 {
2073         ModifyTargetGUI::create_objects(text_box);
2074 }
2075
2076 void ModifyTargetTrackTypeGUI::update()
2077 {
2078         BinFolderTargetTrackType *target = (BinFolderTargetTrackType *)thread->target;
2079         const char *cp = text_box->get_text();
2080         int data_types = 0;
2081         if( bstrcasestr(cp, _("audio")) ) data_types |= (1<<TRACK_AUDIO);
2082         if( bstrcasestr(cp, _("video")) ) data_types |= (1<<TRACK_VIDEO);
2083         target->update(data_types);
2084 }
2085
2086
2087 ModifyTargetWidthGUI::ModifyTargetWidthGUI(ModifyTargetThread *thread)
2088  : ModifyTargetGUI(thread)
2089 {
2090 }
2091
2092 ModifyTargetWidthGUI::~ModifyTargetWidthGUI()
2093 {
2094 }
2095
2096 void ModifyTargetWidthGUI::create_objects()
2097 {
2098         ModifyTargetGUI::create_objects(text_box);
2099 }
2100
2101 void ModifyTargetWidthGUI::update()
2102 {
2103         BinFolderTargetWidth *target = (BinFolderTargetWidth *)thread->target;
2104         double width = target->width, around = target->around;
2105         const char *cp = text_box->get_text();  char *bp = 0;
2106         scan_around(cp, bp, width, around);
2107         target->update(width, around);
2108 }
2109
2110
2111 ModifyTargetHeightGUI::ModifyTargetHeightGUI(ModifyTargetThread *thread)
2112  : ModifyTargetGUI(thread)
2113 {
2114 }
2115
2116 ModifyTargetHeightGUI::~ModifyTargetHeightGUI()
2117 {
2118 }
2119
2120 void ModifyTargetHeightGUI::create_objects()
2121 {
2122         ModifyTargetGUI::create_objects(text_box);
2123 }
2124
2125 void ModifyTargetHeightGUI::update()
2126 {
2127         BinFolderTargetHeight *target = (BinFolderTargetHeight *)thread->target;
2128         double height = target->height, around = target->around;
2129         const char *cp = text_box->get_text();  char *bp = 0;
2130         scan_around(cp, bp, height, around);
2131         target->update(height, around);
2132 }
2133
2134
2135 ModifyTargetFramerateGUI::ModifyTargetFramerateGUI(ModifyTargetThread *thread)
2136  : ModifyTargetGUI(thread)
2137 {
2138 }
2139
2140 ModifyTargetFramerateGUI::~ModifyTargetFramerateGUI()
2141 {
2142 }
2143
2144 void ModifyTargetFramerateGUI::create_objects()
2145 {
2146         ModifyTargetGUI::create_objects(text_box);
2147 }
2148
2149 void ModifyTargetFramerateGUI::update()
2150 {
2151         BinFolderTargetFramerate *target = (BinFolderTargetFramerate *)thread->target;
2152         double framerate = target->framerate, around = target->around;
2153         const char *cp = text_box->get_text();  char *bp = 0;
2154         scan_around(cp, bp, framerate, around);
2155         target->update(framerate, around);
2156 }
2157
2158
2159 ModifyTargetSamplerateGUI::ModifyTargetSamplerateGUI(ModifyTargetThread *thread)
2160  : ModifyTargetGUI(thread)
2161 {
2162 }
2163
2164 ModifyTargetSamplerateGUI::~ModifyTargetSamplerateGUI()
2165 {
2166 }
2167
2168 void ModifyTargetSamplerateGUI::create_objects()
2169 {
2170         ModifyTargetGUI::create_objects(text_box);
2171 }
2172
2173 void ModifyTargetSamplerateGUI::update()
2174 {
2175         BinFolderTargetSamplerate *target = (BinFolderTargetSamplerate *)thread->target;
2176         double samplerate = target->samplerate, around = target->around;
2177         const char *cp = text_box->get_text();  char *bp = 0;
2178         scan_around(cp, bp, samplerate, around);
2179         target->update(samplerate, around);
2180 }
2181
2182
2183 ModifyTargetChannelsGUI::ModifyTargetChannelsGUI(ModifyTargetThread *thread)
2184  : ModifyTargetGUI(thread)
2185 {
2186 }
2187
2188 ModifyTargetChannelsGUI::~ModifyTargetChannelsGUI()
2189 {
2190 }
2191
2192 void ModifyTargetChannelsGUI::create_objects()
2193 {
2194         ModifyTargetGUI::create_objects(text_box);
2195 }
2196
2197 void ModifyTargetChannelsGUI::update()
2198 {
2199         BinFolderTargetChannels *target = (BinFolderTargetChannels *)thread->target;
2200         double channels = target->channels, around = target->around;
2201         const char *cp = text_box->get_text();  char *bp = 0;
2202         scan_around(cp, bp, channels, around);
2203         target->update(channels, around);
2204 }
2205
2206
2207 ModifyTargetDurationGUI::ModifyTargetDurationGUI(ModifyTargetThread *thread)
2208  : ModifyTargetGUI(thread)
2209 {
2210 }
2211
2212 ModifyTargetDurationGUI::~ModifyTargetDurationGUI()
2213 {
2214 }
2215
2216 void ModifyTargetDurationGUI::create_objects()
2217 {
2218         ModifyTargetGUI::create_objects(text_box);
2219 }
2220
2221 void ModifyTargetDurationGUI::update()
2222 {
2223         BinFolderTargetDuration *target = (BinFolderTargetDuration *)thread->target;
2224         int64_t duration = target->duration, around = target->around;
2225         const char *cp = text_box->get_text();  char *bp = 0;
2226         int64_t v = scan_duration(cp, bp);
2227         if( bp > cp ) {
2228                 duration = v;
2229                 if( *bp == '+' ) {
2230                         v = scan_duration(cp=bp+1, bp);
2231                         if( bp > cp ) around = v;
2232                 }
2233         }
2234         target->update(duration, around);
2235 }
2236