538c1e4fce79f95a30bfc991eb257c18dea29cae
[blender.git] / source / blender / editors / space_file / filelist.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2007 Blender Foundation.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30
31 /* global includes */
32
33 #include <stdlib.h>
34 #include <math.h>
35 #include <string.h>
36
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #ifndef WIN32
42 #include <unistd.h>
43 #else
44 #include <io.h>
45 #include <direct.h>
46 #endif   
47 #include "MEM_guardedalloc.h"
48
49 #include "BLI_blenlib.h"
50 #include "BLI_linklist.h"
51 #include "BLI_storage_types.h"
52 #include "BLI_threads.h"
53
54 #ifdef WIN32
55 #include "BLI_winstuff.h"
56 #endif
57
58 #include "BKE_utildefines.h"
59 #include "BKE_global.h"
60 #include "BKE_library.h"
61 #include "BKE_global.h"
62 #include "BKE_main.h"
63 #include "BLO_readfile.h"
64
65 #include "DNA_space_types.h"
66 #include "DNA_ipo_types.h"
67 #include "DNA_ID.h"
68 #include "DNA_object_types.h"
69 #include "DNA_listBase.h"
70 #include "DNA_lamp_types.h"
71 #include "DNA_material_types.h"
72 #include "DNA_texture_types.h"
73 #include "DNA_world_types.h"
74 #include "DNA_scene_types.h"
75 #include "DNA_userdef_types.h"
76
77 #include "ED_datafiles.h"
78
79 #include "IMB_imbuf.h"
80 #include "IMB_imbuf_types.h"
81 #include "IMB_thumbs.h"
82
83 #include "PIL_time.h"
84
85 #include "UI_interface.h"
86
87 #include "filelist.h"
88
89 /* Elubie: VERY, really very ugly and evil! Remove asap!!! */
90 /* for state of file */
91 #define ACTIVE                          2
92
93 /* max length of library group name within filesel */
94 #define GROUP_MAX 32
95
96 static void *exec_loadimages(void *list_v);
97
98 struct FileList;
99
100 typedef struct FileImage {
101         struct FileImage *next, *prev;
102         int index;
103         short lock;
104         short done;
105         struct FileList* filelist;
106 } FileImage;
107
108 typedef struct FileList
109 {
110         struct direntry *filelist;
111         int *fidx;
112
113         int numfiles;
114         int numfiltered;
115         char dir[FILE_MAX];
116         short prv_w;
117         short prv_h;
118         short hide_dot;
119         unsigned int filter;
120         short changed;
121         ListBase loadimages;
122         ListBase threads;
123 } FileList;
124
125 typedef struct FolderList
126 {
127         struct FolderList *next, *prev;
128         char *foldername;
129 } FolderList;
130
131 #define SPECIAL_IMG_SIZE 48
132 #define SPECIAL_IMG_ROWS 4
133 #define SPECIAL_IMG_COLS 4
134
135 #define SPECIAL_IMG_FOLDER 0
136 #define SPECIAL_IMG_PARENT 1
137 #define SPECIAL_IMG_REFRESH 2
138 #define SPECIAL_IMG_BLENDFILE 3
139 #define SPECIAL_IMG_SOUNDFILE 4
140 #define SPECIAL_IMG_MOVIEFILE 5
141 #define SPECIAL_IMG_PYTHONFILE 6
142 #define SPECIAL_IMG_TEXTFILE 7
143 #define SPECIAL_IMG_FONTFILE 8
144 #define SPECIAL_IMG_UNKNOWNFILE 9
145 #define SPECIAL_IMG_LOADING 10
146 #define SPECIAL_IMG_MAX SPECIAL_IMG_LOADING + 1
147
148 static ImBuf* gSpecialFileImages[SPECIAL_IMG_MAX];
149
150
151 /* ******************* SORT ******************* */
152
153 static int compare_name(const void *a1, const void *a2)
154 {
155         const struct direntry *entry1=a1, *entry2=a2;
156
157         /* type is is equal to stat.st_mode */
158
159         if (S_ISDIR(entry1->type)){
160                 if (S_ISDIR(entry2->type)==0) return (-1);
161         } else{
162                 if (S_ISDIR(entry2->type)) return (1);
163         }
164         if (S_ISREG(entry1->type)){
165                 if (S_ISREG(entry2->type)==0) return (-1);
166         } else{
167                 if (S_ISREG(entry2->type)) return (1);
168         }
169         if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
170         if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
171         
172         /* make sure "." and ".." are always first */
173         if( strcmp(entry1->relname, ".")==0 ) return (-1);
174         if( strcmp(entry2->relname, ".")==0 ) return (1);
175         if( strcmp(entry1->relname, "..")==0 ) return (-1);
176         if( strcmp(entry2->relname, "..")==0 ) return (1);
177         
178         return (BLI_natstrcmp(entry1->relname,entry2->relname));
179 }
180
181 static int compare_date(const void *a1, const void *a2) 
182 {
183         const struct direntry *entry1=a1, *entry2=a2;
184         
185         /* type is equal to stat.st_mode */
186
187         if (S_ISDIR(entry1->type)){
188                 if (S_ISDIR(entry2->type)==0) return (-1);
189         } else{
190                 if (S_ISDIR(entry2->type)) return (1);
191         }
192         if (S_ISREG(entry1->type)){
193                 if (S_ISREG(entry2->type)==0) return (-1);
194         } else{
195                 if (S_ISREG(entry2->type)) return (1);
196         }
197         if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
198         if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
199
200         /* make sure "." and ".." are always first */
201         if( strcmp(entry1->relname, ".")==0 ) return (-1);
202         if( strcmp(entry2->relname, ".")==0 ) return (1);
203         if( strcmp(entry1->relname, "..")==0 ) return (-1);
204         if( strcmp(entry2->relname, "..")==0 ) return (1);
205         
206         if ( entry1->s.st_mtime < entry2->s.st_mtime) return 1;
207         if ( entry1->s.st_mtime > entry2->s.st_mtime) return -1;
208         
209         else return BLI_natstrcmp(entry1->relname,entry2->relname);
210 }
211
212 static int compare_size(const void *a1, const void *a2) 
213 {
214         const struct direntry *entry1=a1, *entry2=a2;
215
216         /* type is equal to stat.st_mode */
217
218         if (S_ISDIR(entry1->type)){
219                 if (S_ISDIR(entry2->type)==0) return (-1);
220         } else{
221                 if (S_ISDIR(entry2->type)) return (1);
222         }
223         if (S_ISREG(entry1->type)){
224                 if (S_ISREG(entry2->type)==0) return (-1);
225         } else{
226                 if (S_ISREG(entry2->type)) return (1);
227         }
228         if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
229         if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
230
231         /* make sure "." and ".." are always first */
232         if( strcmp(entry1->relname, ".")==0 ) return (-1);
233         if( strcmp(entry2->relname, ".")==0 ) return (1);
234         if( strcmp(entry1->relname, "..")==0 ) return (-1);
235         if( strcmp(entry2->relname, "..")==0 ) return (1);
236         
237         if ( entry1->s.st_size < entry2->s.st_size) return 1;
238         if ( entry1->s.st_size > entry2->s.st_size) return -1;
239         else return BLI_natstrcmp(entry1->relname,entry2->relname);
240 }
241
242 static int compare_extension(const void *a1, const void *a2) {
243         const struct direntry *entry1=a1, *entry2=a2;
244         char *sufix1, *sufix2;
245         char *nil="";
246
247         if (!(sufix1= strstr (entry1->relname, ".blend.gz"))) 
248                 sufix1= strrchr (entry1->relname, '.');
249         if (!(sufix2= strstr (entry2->relname, ".blend.gz")))
250                 sufix2= strrchr (entry2->relname, '.');
251         if (!sufix1) sufix1= nil;
252         if (!sufix2) sufix2= nil;
253
254         /* type is is equal to stat.st_mode */
255
256         if (S_ISDIR(entry1->type)){
257                 if (S_ISDIR(entry2->type)==0) return (-1);
258         } else{
259                 if (S_ISDIR(entry2->type)) return (1);
260         }
261         if (S_ISREG(entry1->type)){
262                 if (S_ISREG(entry2->type)==0) return (-1);
263         } else{
264                 if (S_ISREG(entry2->type)) return (1);
265         }
266         if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
267         if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
268         
269         /* make sure "." and ".." are always first */
270         if( strcmp(entry1->relname, ".")==0 ) return (-1);
271         if( strcmp(entry2->relname, ".")==0 ) return (1);
272         if( strcmp(entry1->relname, "..")==0 ) return (-1);
273         if( strcmp(entry2->relname, "..")==0 ) return (1);
274         
275         return (BLI_strcasecmp(sufix1, sufix2));
276 }
277
278 void filelist_filter(FileList* filelist)
279 {
280         int num_filtered = 0;
281         int i, j;
282         
283         if (!filelist->filelist)
284                 return;
285         
286         if (!filelist->filter) {
287                 if (filelist->fidx) {
288                         MEM_freeN(filelist->fidx);
289                         filelist->fidx = NULL;
290                 }
291                 filelist->fidx = (int *)MEM_callocN(filelist->numfiles*sizeof(int), "filteridx");
292                 for (i = 0; i < filelist->numfiles; ++i) {
293                         filelist->fidx[i] = i;
294                 }
295                 filelist->numfiltered = filelist->numfiles;
296                 return;
297         }
298
299         // How many files are left after filter ?
300         for (i = 0; i < filelist->numfiles; ++i) {
301                 if (filelist->filelist[i].flags & filelist->filter) {
302                         num_filtered++;
303                 } 
304                 else if (filelist->filelist[i].type & S_IFDIR) {
305                         if (filelist->filter & FOLDERFILE) {
306                                 num_filtered++;
307                         }
308                 }               
309         }
310         
311         if (filelist->fidx) {
312                         MEM_freeN(filelist->fidx);
313                         filelist->fidx = NULL;
314         }
315         filelist->fidx = (int *)MEM_callocN(num_filtered*sizeof(int), "filteridx");
316         filelist->numfiltered = num_filtered;
317
318         for (i = 0, j=0; i < filelist->numfiles; ++i) {
319                 if (filelist->filelist[i].flags & filelist->filter) {
320                         filelist->fidx[j++] = i;
321                 }
322                 else if (filelist->filelist[i].type & S_IFDIR) {
323                         if (filelist->filter & FOLDERFILE) {
324                                 filelist->fidx[j++] = i;
325                         }
326                 }  
327         }
328 }
329
330 void filelist_init_icons()
331 {
332         short x, y, k;
333         ImBuf *bbuf;
334         ImBuf *ibuf;
335         bbuf = IMB_ibImageFromMemory((int *)datatoc_prvicons, datatoc_prvicons_size, IB_rect);
336         if (bbuf) {
337                 for (y=0; y<SPECIAL_IMG_ROWS; y++) {
338                         for (x=0; x<SPECIAL_IMG_COLS; x++) {
339                                 int tile = SPECIAL_IMG_COLS*y + x; 
340                                 if (tile < SPECIAL_IMG_MAX) {
341                                         ibuf = IMB_allocImBuf(SPECIAL_IMG_SIZE, SPECIAL_IMG_SIZE, 32, IB_rect, 0);
342                                         for (k=0; k<SPECIAL_IMG_SIZE; k++) {
343                                                 memcpy(&ibuf->rect[k*SPECIAL_IMG_SIZE], &bbuf->rect[(k+y*SPECIAL_IMG_SIZE)*SPECIAL_IMG_SIZE*SPECIAL_IMG_COLS+x*SPECIAL_IMG_SIZE], SPECIAL_IMG_SIZE*sizeof(int));
344                                         }
345                                         gSpecialFileImages[tile] = ibuf;
346                                 }
347                         }
348                 }
349                 IMB_freeImBuf(bbuf);
350         }
351 }
352
353 void filelist_free_icons()
354 {
355         int i;
356         for (i=0; i < SPECIAL_IMG_MAX; ++i) {
357                 IMB_freeImBuf(gSpecialFileImages[i]);
358                 gSpecialFileImages[i] = NULL;
359         }
360 }
361
362 //-----------------FOLDERLIST (previous/next) --------------//
363 struct ListBase* folderlist_new()
364 {
365         ListBase* p = MEM_callocN( sizeof(ListBase), "folderlist" );
366         return p;
367 }
368
369 void folderlist_popdir(struct ListBase* folderlist, char *dir)
370 {
371         const char *prev_dir;
372         struct FolderList *folder;
373         folder = folderlist->last;
374
375         if(folder){
376                 // remove the current directory
377                 MEM_freeN(folder->foldername);
378                 BLI_freelinkN(folderlist, folder);
379
380                 folder = folderlist->last;
381                 if(folder){
382                         prev_dir = folder->foldername;
383                         BLI_strncpy(dir, prev_dir, FILE_MAXDIR);
384                 }
385         }
386         // delete the folder next or use setdir directly before PREVIOUS OP
387 }
388
389 void folderlist_pushdir(ListBase* folderlist, const char *dir)
390 {
391         struct FolderList *folder, *previous_folder;
392         previous_folder = folderlist->last;
393
394         // check if already exists
395         if(previous_folder){
396                 if(! strcmp(previous_folder->foldername, dir)){
397                         return;
398                 }
399         }
400
401         // create next folder element
402         folder = (FolderList*)MEM_mallocN(sizeof(FolderList),"FolderList");
403         folder->foldername = (char*)MEM_mallocN(sizeof(char)*(strlen(dir)+1), "foldername");
404         folder->foldername[0] = '\0';
405
406         BLI_strncpy(folder->foldername, dir, FILE_MAXDIR);
407
408         // add it to the end of the list
409         BLI_addtail(folderlist, folder);
410 }
411
412 int folderlist_clear_next(struct SpaceFile *sfile)
413 {
414         struct FolderList *folder;
415
416         // if there is no folder_next there is nothing we can clear
417         if (!sfile->folders_next)
418                 return 0;
419
420         // if previous_folder, next_folder or refresh_folder operators are executed it doesn't clear folder_next
421         folder = sfile->folders_prev->last;
422         if ((!folder) ||(!strcmp(folder->foldername, sfile->params->dir)))
423                 return 0;
424
425         // eventually clear flist->folders_next
426         return 1;
427 }
428
429 void folderlist_free(ListBase* folderlist)
430 {
431         FolderList *folder;
432         if (folderlist){
433                 for(folder= folderlist->last; folder; folder= folderlist->last) {
434                                 MEM_freeN(folder->foldername);
435                                 BLI_freelinkN(folderlist, folder);
436                 }
437         }
438         folderlist= NULL;
439 }
440
441 //------------------FILELIST------------------------//
442 struct FileList*        filelist_new()
443 {
444         FileList* p = MEM_callocN( sizeof(FileList), "filelist" );
445         return p;
446 }
447
448 struct FileList*        filelist_copy(struct FileList* filelist)
449 {
450         FileList* p = filelist_new();
451         BLI_strncpy(p->dir, filelist->dir, FILE_MAX);
452         p->filelist = NULL;
453         p->fidx = NULL;
454
455         return p;
456 }
457
458 void filelist_free(struct FileList* filelist)
459 {
460         int i;
461
462         if (!filelist) {
463                 printf("Attempting to delete empty filelist.\n");
464                 return;
465         }
466
467         BLI_end_threads(&filelist->threads);
468         BLI_freelistN(&filelist->loadimages);
469         
470         if (filelist->fidx) {
471                 MEM_freeN(filelist->fidx);
472                 filelist->fidx = NULL;
473         }
474
475         for (i = 0; i < filelist->numfiles; ++i) {
476                 if (filelist->filelist[i].image) {                      
477                         IMB_freeImBuf(filelist->filelist[i].image);
478                 }
479                 filelist->filelist[i].image = 0;
480                 if (filelist->filelist[i].relname)
481                         MEM_freeN(filelist->filelist[i].relname);
482                 filelist->filelist[i].relname = 0;
483                 if (filelist->filelist[i].string)
484                         MEM_freeN(filelist->filelist[i].string);
485                 filelist->filelist[i].string = 0;
486         }
487         
488         filelist->numfiles = 0;
489         free(filelist->filelist);
490         filelist->filelist = 0; 
491         filelist->filter = 0;
492         filelist->numfiltered =0;
493         filelist->hide_dot =0;
494 }
495
496 int     filelist_numfiles(struct FileList* filelist)
497 {
498         return filelist->numfiltered;
499 }
500
501 const char * filelist_dir(struct FileList* filelist)
502 {
503         return filelist->dir;
504 }
505
506 void filelist_setdir(struct FileList* filelist, const char *dir)
507 {
508         BLI_strncpy(filelist->dir, dir, FILE_MAX);
509 }
510
511 void filelist_imgsize(struct FileList* filelist, short w, short h)
512 {
513         filelist->prv_w = w;
514         filelist->prv_h = h;
515 }
516
517
518 static void *exec_loadimages(void *list_v)
519 {
520         FileImage* img = (FileImage*)list_v;
521         struct FileList *filelist = img->filelist;
522
523         ImBuf *imb = NULL;
524         int fidx = img->index;
525         
526         if ( filelist->filelist[fidx].flags & IMAGEFILE ) {                             
527                 imb = IMB_thumb_manage(filelist->dir, filelist->filelist[fidx].relname, THB_NORMAL, THB_SOURCE_IMAGE);
528         } else if ( filelist->filelist[fidx].flags & MOVIEFILE ) {                              
529                 imb = IMB_thumb_manage(filelist->dir, filelist->filelist[fidx].relname, THB_NORMAL, THB_SOURCE_MOVIE);
530                 if (!imb) {
531                         /* remember that file can't be loaded via IMB_open_anim */
532                         filelist->filelist[fidx].flags &= ~MOVIEFILE;
533                         filelist->filelist[fidx].flags |= MOVIEFILE_ICON;
534                 }
535         }
536         if (imb) {
537                 IMB_freeImBuf(imb);
538         }
539         img->done=1;
540         return 0;
541 }
542
543 short filelist_changed(struct FileList* filelist)
544 {
545         return filelist->changed;
546 }
547
548 void filelist_loadimage_timer(struct FileList* filelist)
549 {
550         FileImage *limg = filelist->loadimages.first;
551         short refresh=0;
552
553         // as long as threads are available and there is work to do
554         while (limg) {
555                 if (BLI_available_threads(&filelist->threads)>0) {
556                         if (!limg->lock) {
557                                 limg->lock=1;
558                                 BLI_insert_thread(&filelist->threads, limg);
559                         }
560                 }
561                 if (limg->done) {
562                         FileImage *oimg = limg;
563                         BLI_remlink(&filelist->loadimages, oimg);
564                         BLI_remove_thread(&filelist->threads, oimg);
565                         limg = oimg->next;
566                         MEM_freeN(oimg);
567                         refresh = 1;
568                 } else {
569                         limg= limg->next;
570                 }
571         }
572         filelist->changed=refresh;
573 }
574
575 void filelist_loadimage(struct FileList* filelist, int index)
576 {
577         ImBuf *imb = NULL;
578         int imgwidth = filelist->prv_w;
579         int imgheight = filelist->prv_h;
580         short ex, ey, dx, dy;
581         float scaledx, scaledy;
582         int fidx = 0;
583         
584         if ( (index < 0) || (index >= filelist->numfiltered) ) {
585                 return;
586         }
587         fidx = filelist->fidx[index];
588
589         if (!filelist->filelist[fidx].image)
590         {
591
592                 if ( (filelist->filelist[fidx].flags & IMAGEFILE) || (filelist->filelist[fidx].flags & MOVIEFILE) ) {                           
593                         imb = IMB_thumb_read(filelist->dir, filelist->filelist[fidx].relname, THB_NORMAL);
594                 } 
595                 if (imb) {
596                         if (imb->x > imb->y) {
597                                 scaledx = (float)imgwidth;
598                                 scaledy =  ( (float)imb->y/(float)imb->x )*imgwidth;
599                         }
600                         else {
601                                 scaledy = (float)imgheight;
602                                 scaledx =  ( (float)imb->x/(float)imb->y )*imgheight;
603                         }
604                         ex = (short)scaledx;
605                         ey = (short)scaledy;
606                         
607                         dx = imgwidth - ex;
608                         dy = imgheight - ey;
609                         
610                         // IMB_scaleImBuf(imb, ex, ey);
611                         filelist->filelist[fidx].image = imb;
612                 } else {
613                         /* prevent loading image twice */
614                         FileImage* limg = filelist->loadimages.first;
615                         short found= 0;
616                         while(limg) {
617                                 if (limg->index == fidx) {
618                                         found= 1;
619                                         break;
620                                 }
621                                 limg= limg->next;
622                         }
623                         if (!found) {
624                                 FileImage* limg = MEM_callocN(sizeof(struct FileImage), "loadimage");
625                                 limg->index= fidx;
626                                 limg->lock= 0;
627                                 limg->filelist= filelist;
628                                 BLI_addtail(&filelist->loadimages, limg);
629                         }
630                 }               
631         }
632 }
633
634 struct ImBuf * filelist_getimage(struct FileList* filelist, int index)
635 {
636         ImBuf* ibuf = NULL;
637         int fidx = 0;   
638         if ( (index < 0) || (index >= filelist->numfiltered) ) {
639                 return NULL;
640         }
641         fidx = filelist->fidx[index];
642         ibuf = filelist->filelist[fidx].image;
643
644         return ibuf;
645 }
646
647 struct ImBuf * filelist_geticon(struct FileList* filelist, int index)
648 {
649         ImBuf* ibuf= NULL;
650         struct direntry *file= NULL;
651         int fidx = 0;   
652         if ( (index < 0) || (index >= filelist->numfiltered) ) {
653                 return NULL;
654         }
655         fidx = filelist->fidx[index];
656         file = &filelist->filelist[fidx];
657         if (file->type & S_IFDIR) {
658                         if ( strcmp(filelist->filelist[fidx].relname, "..") == 0) {
659                                 ibuf = gSpecialFileImages[SPECIAL_IMG_PARENT];
660                         } else if  ( strcmp(filelist->filelist[fidx].relname, ".") == 0) {
661                                 ibuf = gSpecialFileImages[SPECIAL_IMG_REFRESH];
662                         } else {
663                 ibuf = gSpecialFileImages[SPECIAL_IMG_FOLDER];
664                         }
665         } else {
666                 ibuf = gSpecialFileImages[SPECIAL_IMG_UNKNOWNFILE];
667         }
668
669         if (file->flags & BLENDERFILE) {
670                 ibuf = gSpecialFileImages[SPECIAL_IMG_BLENDFILE];
671         } else if ( (file->flags & MOVIEFILE) || (file->flags & MOVIEFILE_ICON) ) {
672                 ibuf = gSpecialFileImages[SPECIAL_IMG_MOVIEFILE];
673         } else if (file->flags & SOUNDFILE) {
674                 ibuf = gSpecialFileImages[SPECIAL_IMG_SOUNDFILE];
675         } else if (file->flags & PYSCRIPTFILE) {
676                 ibuf = gSpecialFileImages[SPECIAL_IMG_PYTHONFILE];
677         } else if (file->flags & FTFONTFILE) {
678                 ibuf = gSpecialFileImages[SPECIAL_IMG_FONTFILE];
679         } else if (file->flags & TEXTFILE) {
680                 ibuf = gSpecialFileImages[SPECIAL_IMG_TEXTFILE];
681         } else if (file->flags & IMAGEFILE) {
682                 ibuf = gSpecialFileImages[SPECIAL_IMG_LOADING];
683         }
684
685         return ibuf;
686 }
687
688 struct direntry * filelist_file(struct FileList* filelist, int index)
689 {
690         int fidx = 0;
691         
692         if ( (index < 0) || (index >= filelist->numfiltered) ) {
693                 return NULL;
694         }
695         fidx = filelist->fidx[index];
696
697         return &filelist->filelist[fidx];
698 }
699
700 int filelist_find(struct FileList* filelist, char *file)
701 {
702         int index = -1;
703         int i;
704         int fidx = -1;
705         
706         if (!filelist->fidx) 
707                 return fidx;
708
709         
710         for (i = 0; i < filelist->numfiles; ++i) {
711                 if ( strcmp(filelist->filelist[i].relname, file) == 0) {
712                         index = i;
713                         break;
714                 }
715         }
716
717         for (i = 0; i < filelist->numfiltered; ++i) {
718                 if (filelist->fidx[i] == index) {
719                         fidx = i;
720                         break;
721                 }
722         }
723         return fidx;
724 }
725
726 void filelist_hidedot(struct FileList* filelist, short hide)
727 {
728         filelist->hide_dot = hide;
729 }
730
731 void filelist_setfilter(struct FileList* filelist, unsigned int filter)
732 {
733         filelist->filter = filter;
734 }
735
736 void filelist_readdir(struct FileList* filelist)
737 {
738         char wdir[FILE_MAX];
739
740         if (!filelist) return;
741         filelist->fidx = 0;
742         filelist->filelist = 0;
743
744         BLI_getwdN(wdir);        
745         
746         BLI_cleanup_dir(G.sce, filelist->dir);
747         BLI_hide_dot_files(filelist->hide_dot);
748         filelist->numfiles = BLI_getdir(filelist->dir, &(filelist->filelist));
749
750         chdir(wdir);
751         filelist_setfiletypes(filelist, G.have_quicktime);
752         filelist_filter(filelist);
753         
754         if (!filelist->threads.first) {
755                 BLI_init_threads(&filelist->threads, exec_loadimages, 2);
756         }
757 }
758
759 int filelist_empty(struct FileList* filelist)
760 {       
761         return filelist->filelist == 0;
762 }
763
764 void filelist_parent(struct FileList* filelist)
765 {
766         BLI_parent_dir(filelist->dir);
767         BLI_make_exist(filelist->dir);
768         filelist_readdir(filelist);
769 }
770
771 void filelist_setfiletypes(struct FileList* filelist, short has_quicktime)
772 {
773         struct direntry *file;
774         int num;
775
776         file= filelist->filelist;
777
778         for(num=0; num<filelist->numfiles; num++, file++) {
779                 file->flags= 0;
780                 file->type= file->s.st_mode;    /* restore the mess below */ 
781
782                         /* Don't check extensions for directories */ 
783                 if (file->type & S_IFDIR)
784                         continue;
785                                 
786                 
787                 
788                 if(BLO_has_bfile_extension(file->relname)) {
789                         file->flags |= BLENDERFILE;
790                 } else if(BLI_testextensie(file->relname, ".py")) {
791                                 file->flags |= PYSCRIPTFILE;
792                 } else if(BLI_testextensie(file->relname, ".txt")) {
793                                 file->flags |= TEXTFILE;
794                 } else if( BLI_testextensie(file->relname, ".ttf")
795                                         || BLI_testextensie(file->relname, ".ttc")
796                                         || BLI_testextensie(file->relname, ".pfb")
797                                         || BLI_testextensie(file->relname, ".otf")
798                                         || BLI_testextensie(file->relname, ".otc")) {
799                                 file->flags |= FTFONTFILE;                      
800                 } else if (has_quicktime){
801                         if(             BLI_testextensie(file->relname, ".int")
802                                 ||  BLI_testextensie(file->relname, ".inta")
803                                 ||  BLI_testextensie(file->relname, ".jpg")
804 #ifdef WITH_OPENJPEG
805                                 ||  BLI_testextensie(file->relname, ".jp2")
806 #endif
807                                 ||      BLI_testextensie(file->relname, ".jpeg")
808                                 ||      BLI_testextensie(file->relname, ".tga")
809                                 ||      BLI_testextensie(file->relname, ".rgb")
810                                 ||      BLI_testextensie(file->relname, ".rgba")
811                                 ||      BLI_testextensie(file->relname, ".bmp")
812                                 ||      BLI_testextensie(file->relname, ".png")
813                                 ||      BLI_testextensie(file->relname, ".iff")
814                                 ||      BLI_testextensie(file->relname, ".lbm")
815                                 ||      BLI_testextensie(file->relname, ".gif")
816                                 ||      BLI_testextensie(file->relname, ".psd")
817                                 ||      BLI_testextensie(file->relname, ".tif")
818                                 ||      BLI_testextensie(file->relname, ".tiff")
819                                 ||      BLI_testextensie(file->relname, ".pct")
820                                 ||      BLI_testextensie(file->relname, ".pict")
821                                 ||      BLI_testextensie(file->relname, ".pntg") //macpaint
822                                 ||      BLI_testextensie(file->relname, ".qtif")
823                                 ||      BLI_testextensie(file->relname, ".sgi")
824                                 ||      BLI_testextensie(file->relname, ".hdr")
825 #ifdef WITH_DDS
826                                 ||      BLI_testextensie(file->relname, ".dds")
827 #endif
828 #ifdef WITH_OPENEXR
829                                 ||      BLI_testextensie(file->relname, ".exr")
830 #endif
831                             ) {
832                                 file->flags |= IMAGEFILE;                       
833                         }
834                         else if(BLI_testextensie(file->relname, ".avi")
835                                 ||      BLI_testextensie(file->relname, ".flc")
836                                 ||      BLI_testextensie(file->relname, ".mov")
837                                 ||      BLI_testextensie(file->relname, ".movie")
838                                 ||      BLI_testextensie(file->relname, ".mp4")
839                                 ||      BLI_testextensie(file->relname, ".m4v")
840                                 ||      BLI_testextensie(file->relname, ".mv")) {
841                                 file->flags |= MOVIEFILE;                       
842                         }
843                         else if(BLI_testextensie(file->relname, ".wav")
844                                 ||      BLI_testextensie(file->relname, ".ogg")
845                                 ||      BLI_testextensie(file->relname, ".oga")
846                                 ||      BLI_testextensie(file->relname, ".mp3")
847                                 ||      BLI_testextensie(file->relname, ".mp2")
848                                 ||      BLI_testextensie(file->relname, ".ac3")
849                                 ||      BLI_testextensie(file->relname, ".aac")
850                                 ||      BLI_testextensie(file->relname, ".flac")
851                                 ||      BLI_testextensie(file->relname, ".wma")
852                                 ||      BLI_testextensie(file->relname, ".eac3")) {
853                                 file->flags |= SOUNDFILE;
854                         }
855                 } else { // no quicktime
856                         if(BLI_testextensie(file->relname, ".int")
857                                 ||      BLI_testextensie(file->relname, ".inta")
858                                 ||      BLI_testextensie(file->relname, ".jpg")
859                                 ||  BLI_testextensie(file->relname, ".jpeg")
860 #ifdef WITH_OPENJPEG
861                                 ||  BLI_testextensie(file->relname, ".jp2")
862 #endif
863                                 ||      BLI_testextensie(file->relname, ".tga")
864                                 ||      BLI_testextensie(file->relname, ".rgb")
865                                 ||      BLI_testextensie(file->relname, ".rgba")
866                                 ||      BLI_testextensie(file->relname, ".bmp")
867                                 ||      BLI_testextensie(file->relname, ".png")
868                                 ||      BLI_testextensie(file->relname, ".iff")
869                                 ||      BLI_testextensie(file->relname, ".tif")
870                                 ||      BLI_testextensie(file->relname, ".tiff")
871                                 ||      BLI_testextensie(file->relname, ".hdr")
872 #ifdef WITH_DDS
873                                 ||      BLI_testextensie(file->relname, ".dds")
874 #endif
875 #ifdef WITH_OPENEXR
876                                 ||      BLI_testextensie(file->relname, ".exr")
877 #endif
878                                 ||      BLI_testextensie(file->relname, ".lbm")
879                                 ||      BLI_testextensie(file->relname, ".sgi")) {
880                                 file->flags |= IMAGEFILE;                       
881                         }
882                         else if(BLI_testextensie(file->relname, ".avi")
883                                 ||      BLI_testextensie(file->relname, ".mp4")
884                                 ||      BLI_testextensie(file->relname, ".mv")) {
885                                 file->flags |= MOVIEFILE;                       
886                         }
887                         else if(BLI_testextensie(file->relname, ".wav")
888                                 ||      BLI_testextensie(file->relname, ".ogg")
889                                 ||      BLI_testextensie(file->relname, ".oga")
890                                 ||      BLI_testextensie(file->relname, ".mp3")
891                                 ||      BLI_testextensie(file->relname, ".mp2")
892                                 ||      BLI_testextensie(file->relname, ".ac3")
893                                 ||      BLI_testextensie(file->relname, ".aac")
894                                 ||      BLI_testextensie(file->relname, ".flac")
895                                 ||      BLI_testextensie(file->relname, ".wma")
896                                 ||      BLI_testextensie(file->relname, ".eac3")) {
897                                 file->flags |= SOUNDFILE;
898                         }
899                 }
900         }
901 }
902
903 void filelist_swapselect(struct FileList* filelist)
904 {
905         struct direntry *file;
906         int num, act= 0;
907         
908         file= filelist->filelist;
909         for(num=0; num<filelist->numfiles; num++, file++) {
910                 if(file->flags & ACTIVE) {
911                         act= 1;
912                         break;
913                 }
914         }
915         file= filelist->filelist+2;
916         for(num=2; num<filelist->numfiles; num++, file++) {
917                 if(act) file->flags &= ~ACTIVE;
918                 else file->flags |= ACTIVE;
919         }
920 }
921
922 void filelist_sort(struct FileList* filelist, short sort)
923 {
924         switch(sort) {
925         case FILE_SORT_ALPHA:
926                 qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_name);   
927                 break;
928         case FILE_SORT_TIME:
929                 qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_date);   
930                 break;
931         case FILE_SORT_SIZE:
932                 qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_size);   
933                 break;
934         case FILE_SORT_EXTENSION:
935                 qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_extension);      
936         }
937
938         filelist_filter(filelist);
939 }