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