Three fixes in 1 commit; (reports 3183 3201 3203)
[blender.git] / source / blender / src / filesel.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL 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. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32
33 #include <stdlib.h>
34 #include <string.h>
35 #include <math.h>
36
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #ifdef WIN32
42 #include <io.h>
43 #include <direct.h>
44 #include "BLI_winstuff.h"
45 #else
46 #include <unistd.h>
47 #include <sys/times.h>
48 #endif   
49
50 #include <sys/stat.h>
51 #include <sys/types.h>
52 #include "MEM_guardedalloc.h"
53
54 #include "BMF_Api.h"
55
56 #include "BLI_blenlib.h"
57 #include "BLI_arithb.h"
58 #include "BLI_linklist.h"
59 #include "BLI_storage_types.h"
60 #include "BLI_dynstr.h"
61
62 #include "IMB_imbuf.h"
63
64 #include "DNA_curve_types.h"
65 #include "DNA_image_types.h"
66 #include "DNA_ipo_types.h"
67 #include "DNA_vfont_types.h"
68 #include "DNA_material_types.h"
69 #include "DNA_mesh_types.h"
70 #include "DNA_object_types.h"
71 #include "DNA_texture_types.h"
72 #include "DNA_space_types.h"
73 #include "DNA_scene_types.h"
74 #include "DNA_screen_types.h"
75 #include "DNA_view3d_types.h"
76 #include "DNA_userdef_types.h"
77
78 #include "BKE_utildefines.h"
79 #include "BKE_global.h"
80 #include "BKE_main.h"
81 #include "BKE_library.h"
82 #include "BKE_curve.h"
83 #include "BKE_font.h"
84 #include "BKE_material.h"
85
86 #include "BIF_gl.h"
87 #include "BIF_interface.h"
88 #include "BIF_toolbox.h"
89 #include "BIF_mywindow.h"
90 #include "BIF_editview.h"
91 #include "BIF_space.h"
92 #include "BIF_screen.h"
93 #include "BIF_resources.h"
94
95 #include "BLO_readfile.h"
96
97 #include "BDR_editcurve.h"
98 #include "BPI_script.h"
99 #include "BSE_filesel.h"
100 #include "BSE_view.h"
101
102 #include "mydevice.h"
103 #include "blendef.h"
104 #include "nla.h"
105
106 #include "BIF_fsmenu.h"  /* include ourselves */
107
108 #if defined WIN32 || defined __BeOS
109         int fnmatch(){return 0;}
110 #else
111         #include <fnmatch.h>
112 #endif
113
114 #ifndef WIN32
115 #include <sys/param.h>
116 #endif
117
118 #define FILESELHEAD             60
119 #define FILESEL_DY              16
120
121 /* for events */
122 #define NOTACTIVE                       0
123 #define ACTIVATE                        1
124 #define INACTIVATE                      2
125 /* for state of file */
126 #define ACTIVE                          2
127
128 #define STARTSWITH(x, y) (strncmp(x, y, sizeof(x) - 1) == 0)
129
130 static int is_a_library(SpaceFile *sfile, char *dir, char *group);
131 static void do_library_append(SpaceFile *sfile);
132 static void library_to_filelist(SpaceFile *sfile);
133 static void filesel_select_objects(struct SpaceFile *sfile);
134 static void active_file_object(struct SpaceFile *sfile);
135 static int groupname_to_code(char *group);
136
137 extern void countall(void);
138
139 /* local globals */
140
141 static rcti scrollrct, textrct, bar;
142 static int filebuty1, filebuty2, page_ofs, collumwidth, selecting=0;
143 static int filetoname= 0;
144 static float pixels_to_ofs;
145 static char otherdir[FILE_MAXDIR];
146 static ScrArea *otherarea;
147
148 /* FSMENU HANDLING */
149
150         /* FSMenuEntry's without paths indicate seperators */
151 typedef struct _FSMenuEntry FSMenuEntry;
152 struct _FSMenuEntry {
153         FSMenuEntry *next;
154
155         char *path;
156 };
157
158 static FSMenuEntry *fsmenu= 0;
159
160 int fsmenu_get_nentries(void)
161 {
162         FSMenuEntry *fsme;
163         int count= 0;
164
165         for (fsme= fsmenu; fsme; fsme= fsme->next) 
166                 count++;
167
168         return count;
169 }
170 int fsmenu_is_entry_a_seperator(int idx)
171 {
172         FSMenuEntry *fsme;
173
174         for (fsme= fsmenu; fsme && idx; fsme= fsme->next)
175                 idx--;
176
177         return (fsme && !fsme->path)?1:0;
178 }
179 char *fsmenu_get_entry(int idx)
180 {
181         FSMenuEntry *fsme;
182
183         for (fsme= fsmenu; fsme && idx; fsme= fsme->next)
184                 idx--;
185
186         return fsme?fsme->path:NULL;
187 }
188 char *fsmenu_build_menu(void)
189 {
190         DynStr *ds= BLI_dynstr_new();
191         FSMenuEntry *fsme;
192         char *menustr;
193
194         for (fsme= fsmenu; fsme; fsme= fsme->next) {
195                 if (!fsme->path) {
196                                 /* clean consecutive seperators and ignore trailing ones */
197                         if (fsme->next) {
198                                 if (fsme->next->path) {
199                                         BLI_dynstr_append(ds, "%l|");
200                                 } else {
201                                         FSMenuEntry *next= fsme->next;
202                                         fsme->next= next->next;
203                                         MEM_freeN(next);
204                                 }
205                         }
206                 } else {
207                         BLI_dynstr_append(ds, fsme->path);
208                         if (fsme->next) BLI_dynstr_append(ds, "|");
209                 }
210         }
211
212         menustr= BLI_dynstr_get_cstring(ds);
213         BLI_dynstr_free(ds);
214         return menustr;
215 }
216 static FSMenuEntry *fsmenu_get_last_separator(void) 
217 {
218         FSMenuEntry *fsme, *lsep=NULL;
219
220         for (fsme= fsmenu; fsme; fsme= fsme->next)
221                 if (!fsme->path)
222                         lsep= fsme;
223
224         return lsep;
225 }
226 void fsmenu_insert_entry(char *path, int sorted)
227 {
228         FSMenuEntry *prev= fsmenu_get_last_separator();
229         FSMenuEntry *fsme= prev?prev->next:fsmenu;
230
231         for (; fsme; prev= fsme, fsme= fsme->next) {
232                 if (fsme->path) {
233                         if (BLI_streq(path, fsme->path)) {
234                                 return;
235                         } else if (sorted && strcmp(path, fsme->path)<0) {
236                                 break;
237                         }
238                 }
239         }
240         
241         fsme= MEM_mallocN(sizeof(*fsme), "fsme");
242         fsme->path= BLI_strdup(path);
243
244         if (prev) {
245                 fsme->next= prev->next;
246                 prev->next= fsme;
247         } else {
248                 fsme->next= fsmenu;
249                 fsmenu= fsme;
250         }
251 }
252 void fsmenu_append_seperator(void)
253 {
254         if (fsmenu) {
255                 FSMenuEntry *fsme= fsmenu;
256
257                 while (fsme->next) fsme= fsme->next;
258
259                 fsme->next= MEM_mallocN(sizeof(*fsme), "fsme");
260                 fsme->next->next= NULL;
261                 fsme->next->path= NULL;
262         }
263 }
264 void fsmenu_remove_entry(int idx)
265 {
266         FSMenuEntry *prev= NULL, *fsme= fsmenu;
267
268         for (fsme= fsmenu; fsme && idx; prev= fsme, fsme= fsme->next)
269                 if (fsme->path)
270                         idx--;
271
272         if (fsme) {
273                 if (prev) {
274                         prev->next= fsme->next;
275                 } else {
276                         fsmenu= fsme->next;
277                 }
278
279                 MEM_freeN(fsme->path);
280                 MEM_freeN(fsme);
281         }
282 }
283 void fsmenu_free(void)
284 {
285         FSMenuEntry *fsme= fsmenu;
286
287         while (fsme) {
288                 FSMenuEntry *n= fsme->next;
289
290                 if (fsme->path) MEM_freeN(fsme->path);
291                 MEM_freeN(fsme);
292
293                 fsme= n;
294         }
295 }
296
297 /* ******************* SORT ******************* */
298
299 static int compare_name(const void *a1, const void *a2)
300 {
301         const struct direntry *entry1=a1, *entry2=a2;
302
303         /* type is is equal to stat.st_mode */
304
305         if (S_ISDIR(entry1->type)){
306                 if (S_ISDIR(entry2->type)==0) return (-1);
307         } else{
308                 if (S_ISDIR(entry2->type)) return (1);
309         }
310         if (S_ISREG(entry1->type)){
311                 if (S_ISREG(entry2->type)==0) return (-1);
312         } else{
313                 if (S_ISREG(entry2->type)) return (1);
314         }
315         if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
316         if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
317         
318         /* make sure "." and ".." are always first */
319         if( strcmp(entry1->relname, ".")==0 ) return (-1);
320         if( strcmp(entry2->relname, ".")==0 ) return (1);
321         if( strcmp(entry1->relname, "..")==0 ) return (-1);
322         
323         return (BLI_strcasecmp(entry1->relname,entry2->relname));
324 }
325
326 static int compare_date(const void *a1, const void *a2) 
327 {
328         const struct direntry *entry1=a1, *entry2=a2;
329         
330         /* type is equal to stat.st_mode */
331
332         if (S_ISDIR(entry1->type)){
333                 if (S_ISDIR(entry2->type)==0) return (-1);
334         } else{
335                 if (S_ISDIR(entry2->type)) return (1);
336         }
337         if (S_ISREG(entry1->type)){
338                 if (S_ISREG(entry2->type)==0) return (-1);
339         } else{
340                 if (S_ISREG(entry2->type)) return (1);
341         }
342         if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
343         if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
344
345         /* make sure "." and ".." are always first */
346         if( strcmp(entry1->relname, ".")==0 ) return (-1);
347         if( strcmp(entry2->relname, ".")==0 ) return (1);
348         if( strcmp(entry1->relname, "..")==0 ) return (-1);
349         
350         if ( entry1->s.st_mtime < entry2->s.st_mtime) return 1;
351         if ( entry1->s.st_mtime > entry2->s.st_mtime) return -1;
352         
353         else return BLI_strcasecmp(entry1->relname,entry2->relname);
354 }
355
356 static int compare_size(const void *a1, const void *a2) 
357 {
358         const struct direntry *entry1=a1, *entry2=a2;
359
360         /* type is equal to stat.st_mode */
361
362         if (S_ISDIR(entry1->type)){
363                 if (S_ISDIR(entry2->type)==0) return (-1);
364         } else{
365                 if (S_ISDIR(entry2->type)) return (1);
366         }
367         if (S_ISREG(entry1->type)){
368                 if (S_ISREG(entry2->type)==0) return (-1);
369         } else{
370                 if (S_ISREG(entry2->type)) return (1);
371         }
372         if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
373         if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
374
375         /* make sure "." and ".." are always first */
376         if( strcmp(entry1->relname, ".")==0 ) return (-1);
377         if( strcmp(entry2->relname, ".")==0 ) return (1);
378         if( strcmp(entry1->relname, "..")==0 ) return (-1);
379         
380         if ( entry1->s.st_size < entry2->s.st_size) return 1;
381         if ( entry1->s.st_size > entry2->s.st_size) return -1;
382         else return BLI_strcasecmp(entry1->relname,entry2->relname);
383 }
384
385 static int compare_extension(const void *a1, const void *a2) {
386         const struct direntry *entry1=a1, *entry2=a2;
387         char *sufix1, *sufix2;
388         char *nil="";
389
390         if (!(sufix1= strstr (entry1->relname, ".blend.gz"))) 
391                 sufix1= strrchr (entry1->relname, '.');
392         if (!(sufix2= strstr (entry2->relname, ".blend.gz")))
393                 sufix2= strrchr (entry2->relname, '.');
394         if (!sufix1) sufix1= nil;
395         if (!sufix2) sufix2= nil;
396
397         /* type is is equal to stat.st_mode */
398
399         if (S_ISDIR(entry1->type)){
400                 if (S_ISDIR(entry2->type)==0) return (-1);
401         } else{
402                 if (S_ISDIR(entry2->type)) return (1);
403         }
404         if (S_ISREG(entry1->type)){
405                 if (S_ISREG(entry2->type)==0) return (-1);
406         } else{
407                 if (S_ISREG(entry2->type)) return (1);
408         }
409         if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
410         if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
411         
412         /* make sure "." and ".." are always first */
413         if( strcmp(entry1->relname, ".")==0 ) return (-1);
414         if( strcmp(entry2->relname, ".")==0 ) return (1);
415         if( strcmp(entry1->relname, "..")==0 ) return (-1);
416         if( strcmp(entry2->relname, "..")==0 ) return (-1);
417         
418         return (BLI_strcasecmp(sufix1, sufix2));
419 }
420
421 /* **************************************** */
422
423 void clear_global_filesel_vars()
424 {
425         selecting= 0;
426 }
427
428
429 void filesel_statistics(SpaceFile *sfile, int *totfile, int *selfile, float *totlen, float *sellen)
430 {
431         double len;
432         int a;
433         
434         *totfile= *selfile= 0;
435         *totlen= *sellen= 0;
436         
437         if(sfile->filelist==0) return;
438         
439         for(a=0; a<sfile->totfile; a++) {
440                 if( (sfile->filelist[a].type & S_IFDIR)==0 ) {
441                         (*totfile) ++;
442
443                         len = sfile->filelist[a].s.st_size;
444                         (*totlen) += (float)(len/1048576.0);            
445
446                         if(sfile->filelist[a].flags & ACTIVE) {
447                                 (*selfile) ++;
448                                 (*sellen) += (float)(len/1048576.0);
449                         }
450                 }
451         }
452 }
453
454 /* *************** HELP FUNCTIONS ******************* */
455
456 /* This is a really ugly function... its purpose is to
457  * take the space file name and clean it up, replacing
458  * excess file entry stuff (like /tmp/../tmp/../)
459  */
460
461 void checkdir(char *dir)
462 {
463         short a;
464         char *start, *eind;
465         char tmp[FILE_MAXDIR+FILE_MAXFILE];
466
467         BLI_make_file_string(G.sce, tmp, dir, "");
468         strcpy(dir, tmp);
469         
470 #ifdef WIN32
471         if(dir[0]=='.') {       /* happens for example in FILE_MAIN */
472                 dir[0]= '\\';
473                 dir[1]= 0;
474                 return;
475         }       
476
477         while ( (start = strstr(dir, "\\..\\")) ) {
478                 eind = start + strlen("\\..\\") - 1;
479                 a = start-dir-1;
480                 while (a>0) {
481                         if (dir[a] == '\\') break;
482                         a--;
483                 }
484                 strcpy(dir+a,eind);
485         }
486
487         while ( (start = strstr(dir,"\\.\\")) ){
488                 eind = start + strlen("\\.\\") - 1;
489                 strcpy(start,eind);
490         }
491
492         while ( (start = strstr(dir,"\\\\" )) ){
493                 eind = start + strlen("\\\\") - 1;
494                 strcpy(start,eind);
495         }
496
497         if((a = strlen(dir))){                          /* remove the '\\' at the end */
498                 while(a>0 && dir[a-1] == '\\'){
499                         a--;
500                         dir[a] = 0;
501                 }
502         }
503
504         strcat(dir, "\\");
505 #else   
506         if(dir[0]=='.') {       /* happens, for example in FILE_MAIN */
507                 dir[0]= '/';
508                 dir[1]= 0;
509                 return;
510         }       
511         
512         while ( (start = strstr(dir, "/../")) ) {
513                 eind = start + strlen("/../") - 1;
514                 a = start-dir-1;
515                 while (a>0) {
516                         if (dir[a] == '/') break;
517                         a--;
518                 }
519                 strcpy(dir+a,eind);
520         }
521
522         while ( (start = strstr(dir,"/./")) ){
523                 eind = start + strlen("/./") - 1;
524                 strcpy(start,eind);
525         }
526
527         while ( (start = strstr(dir,"//" )) ){
528                 eind = start + strlen("//") - 1;
529                 strcpy(start,eind);
530         }
531
532         if( (a = strlen(dir)) ){                                /* remove all '/' at the end */
533                 while(dir[a-1] == '/'){
534                         a--;
535                         dir[a] = 0;
536                         if (a<=0) break;
537                 }
538         }
539
540         strcat(dir, "/");
541 #endif
542 }
543
544 /* not called when browsing .blend itself */
545 void test_flags_file(SpaceFile *sfile)
546 {
547         struct direntry *file;
548         int num;
549
550         file= sfile->filelist;
551         
552         for(num=0; num<sfile->totfile; num++, file++) {
553                 file->flags= 0;
554                 file->type= file->s.st_mode;    /* restore the mess below */ 
555
556                         /* Don't check extensions for directories */ 
557                 if (file->type & S_IFDIR)
558                         continue;
559                         
560                 if(sfile->type==FILE_BLENDER || sfile->type==FILE_LOADLIB) {
561                         if(BLO_has_bfile_extension(file->relname)) {
562                                 file->flags |= BLENDERFILE;
563                                 
564                                 if(sfile->type==FILE_LOADLIB) {
565                                         char name[FILE_MAXDIR+FILE_MAXFILE];
566                                         strcpy(name, sfile->dir);
567                                         strcat(name, file->relname);
568                                         
569                                         /* prevent current file being used as acceptable dir */
570                                         if (BLI_streq(G.main->name, name)==0) {
571                                                 file->type &= ~S_IFMT;
572                                                 file->type |= S_IFDIR;
573                                         }
574                                 }
575                         }
576                 } else if (sfile->type==FILE_SPECIAL){
577                         if(BLI_testextensie(file->relname, ".py")) {
578                                 file->flags |= PYSCRIPTFILE;                    
579                         } else if( BLI_testextensie(file->relname, ".ttf")
580                                         || BLI_testextensie(file->relname, ".ttc")
581                                         || BLI_testextensie(file->relname, ".pfb")
582                                         || BLI_testextensie(file->relname, ".otf")
583                                         || BLI_testextensie(file->relname, ".otc")) {
584                                 file->flags |= FTFONTFILE;                      
585                         } else if (G.have_quicktime){
586                                 if(             BLI_testextensie(file->relname, ".jpg")
587                                         ||      BLI_testextensie(file->relname, ".jpeg")
588                                         ||      BLI_testextensie(file->relname, ".tga")
589                                         ||      BLI_testextensie(file->relname, ".rgb")
590                                         ||      BLI_testextensie(file->relname, ".bmp")
591                                         ||      BLI_testextensie(file->relname, ".png")
592                                         ||      BLI_testextensie(file->relname, ".iff")
593                                         ||      BLI_testextensie(file->relname, ".lbm")
594                                         ||      BLI_testextensie(file->relname, ".gif")
595                                         ||      BLI_testextensie(file->relname, ".psd")
596                                         ||      BLI_testextensie(file->relname, ".tif")
597                                         ||      BLI_testextensie(file->relname, ".tiff")
598                                         ||      BLI_testextensie(file->relname, ".pct")
599                                         ||      BLI_testextensie(file->relname, ".pict")
600                                         ||      BLI_testextensie(file->relname, ".pntg") //macpaint
601                                         ||      BLI_testextensie(file->relname, ".qtif")
602                                         ||      BLI_testextensie(file->relname, ".sgi")) {
603                                         file->flags |= IMAGEFILE;                       
604                                 }
605                                 else if(BLI_testextensie(file->relname, ".avi")
606                                         ||      BLI_testextensie(file->relname, ".flc")
607                                         ||      BLI_testextensie(file->relname, ".mov")
608                                         ||      BLI_testextensie(file->relname, ".movie")
609                                         ||      BLI_testextensie(file->relname, ".mv")) {
610                                         file->flags |= MOVIEFILE;                       
611                                 }
612                         } else { // no quicktime
613                                 if(BLI_testextensie(file->relname, ".jpg")
614                                         ||      BLI_testextensie(file->relname, ".tga")
615                                         ||      BLI_testextensie(file->relname, ".rgb")
616                                         ||      BLI_testextensie(file->relname, ".bmp")
617                                         ||      BLI_testextensie(file->relname, ".png")
618                                         ||      BLI_testextensie(file->relname, ".iff")
619                                         ||      BLI_testextensie(file->relname, ".lbm")
620                                         ||      BLI_testextensie(file->relname, ".sgi")) {
621                                         file->flags |= IMAGEFILE;                       
622                                 }
623                                 else if(BLI_testextensie(file->relname, ".avi")
624                                         ||      BLI_testextensie(file->relname, ".mv")) {
625                                         file->flags |= MOVIEFILE;                       
626                                 }
627                                 else if(BLI_testextensie(file->relname, ".wav")) {
628                                         file->flags |= SOUNDFILE;
629                                 }                               
630                         }
631                 }
632         }       
633 }
634
635
636 void sort_filelist(SpaceFile *sfile)
637 {
638         struct direntry *file;
639         int num;/*  , act= 0; */
640         
641         switch(sfile->sort) {
642         case FILE_SORTALPHA:
643                 qsort(sfile->filelist, sfile->totfile, sizeof(struct direntry), compare_name);  
644                 break;
645         case FILE_SORTDATE:
646                 qsort(sfile->filelist, sfile->totfile, sizeof(struct direntry), compare_date);  
647                 break;
648         case FILE_SORTSIZE:
649                 qsort(sfile->filelist, sfile->totfile, sizeof(struct direntry), compare_size);  
650                 break;
651         case FILE_SORTEXTENS:
652                 qsort(sfile->filelist, sfile->totfile, sizeof(struct direntry), compare_extension);     
653         }
654         
655         sfile->act= -1;
656
657         file= sfile->filelist;
658         for(num=0; num<sfile->totfile; num++, file++) {
659                 file->flags &= ~HILITE;
660         }
661
662 }
663
664 void read_dir(SpaceFile *sfile)
665 {
666         int num, len;
667         char wdir[FILE_MAXDIR];
668
669         /* sfile->act is used for example in databrowse: double names of library objects */
670         sfile->act= -1;
671
672         if(sfile->type==FILE_MAIN) {
673                 main_to_filelist(sfile);
674                 return;
675         }
676         else if(sfile->type==FILE_LOADLIB) {
677                 library_to_filelist(sfile);
678                 if(sfile->libfiledata) return;
679         }
680
681         BLI_hide_dot_files(sfile->flag & FILE_HIDE_DOT);
682         
683         BLI_getwdN(wdir);
684         sfile->totfile= BLI_getdir(sfile->dir, &(sfile->filelist));
685         chdir(wdir);
686         
687         if(sfile->sort!=FILE_SORTALPHA) sort_filelist(sfile);
688         
689         sfile->maxnamelen= 0;
690
691         for (num=0; num<sfile->totfile; num++) {
692                 
693                 len = BMF_GetStringWidth(G.font, sfile->filelist[num].relname);
694                 if (len > sfile->maxnamelen) sfile->maxnamelen = len;
695                 
696                 if(filetoname) {
697                         if(strcmp(sfile->file, sfile->filelist[num].relname)==0) {
698                                 
699                                 sfile->ofs= num-( sfile->collums*(curarea->winy-FILESELHEAD-20)/(2*FILESEL_DY));
700                                 filetoname= 0;
701                         }
702                 }
703         }
704         test_flags_file(sfile);
705         
706         filetoname= 0;
707 }
708
709 void freefilelist(SpaceFile *sfile)
710 {
711         int num;
712
713         num= sfile->totfile-1;
714
715         if (sfile->filelist==0) return;
716         
717         for(; num>=0; num--){
718                 MEM_freeN(sfile->filelist[num].relname);
719                 
720                 if (sfile->filelist[num].string) MEM_freeN(sfile->filelist[num].string);
721         }
722         free(sfile->filelist);
723         sfile->filelist= 0;
724 }
725
726 static void split_sfile(SpaceFile *sfile, char *s1)
727 {
728         char string[FILE_MAXDIR+FILE_MAXFILE], dir[FILE_MAXDIR], file[FILE_MAXFILE];
729
730         strcpy(string, s1);
731
732         BLI_split_dirfile(string, dir, file);
733         
734         if(sfile->filelist) {
735                 if(strcmp(dir, sfile->dir)!=0) {
736                         freefilelist(sfile);
737                 }
738                 else test_flags_file(sfile);
739         }
740         strcpy(sfile->file, file);
741                 
742         BLI_make_file_string(G.sce, sfile->dir, dir, "");
743 }
744
745
746 void parent(SpaceFile *sfile)
747 {
748         short a;
749         char *dir;
750         
751         /* if databrowse: no parent */
752         if(sfile->type==FILE_MAIN && sfile->returnfunc) return;
753
754         dir= sfile->dir;
755         
756 #ifdef WIN32
757         if( (a = strlen(dir)) ) {                               /* remove all '/' at the end */
758                 while(dir[a-1] == '\\') {
759                         a--;
760                         dir[a] = 0;
761                         if (a<=0) break;
762                 }
763         }
764         if( (a = strlen(dir)) ) {                               /* then remove all until '/' */
765                 while(dir[a-1] != '\\') {
766                         a--;
767                         dir[a] = 0;
768                         if (a<=0) break;
769                 }
770         }
771         if( (a = strlen(dir)) ) {
772                 if (dir[a-1] != '\\') strcat(dir,"\\");
773         }
774         else if(sfile->type!=FILE_MAIN) strcpy(dir,"\\");
775 #else
776         if( (a = strlen(dir)) ) {                               /* remove all '/' at the end */
777                 while(dir[a-1] == '/') {
778                         a--;
779                         dir[a] = 0;
780                         if (a<=0) break;
781                 }
782         }
783         if( (a = strlen(dir)) ) {                               /* then remove until '/' */
784                 while(dir[a-1] != '/') {
785                         a--;
786                         dir[a] = 0;
787                         if (a<=0) break;
788                 }
789         }
790         if ( (a = strlen(dir)) ) {
791                 if (dir[a-1] != '/') strcat(dir,"/");
792         }
793         else if(sfile->type!=FILE_MAIN) strcpy(dir,"/");
794 #endif
795         
796         /* to be sure */
797         BLI_make_exist(sfile->dir);
798
799         freefilelist(sfile);
800         sfile->ofs= 0;
801         scrarea_queue_winredraw(curarea);
802 }
803
804 void swapselect_file(SpaceFile *sfile)
805 {
806         struct direntry *file;
807         int num, act= 0;
808         
809         file= sfile->filelist;
810         for(num=0; num<sfile->totfile; num++, file++) {
811                 if(file->flags & ACTIVE) {
812                         act= 1;
813                         break;
814                 }
815         }
816         file= sfile->filelist+2;
817         for(num=2; num<sfile->totfile; num++, file++) {
818                 if(act) file->flags &= ~ACTIVE;
819                 else file->flags |= ACTIVE;
820         }
821 }
822
823 static int find_active_file(SpaceFile *sfile, short x, short y)
824 {
825         int ofs;
826         
827         if(y > textrct.ymax) y= textrct.ymax;
828         if(y <= textrct.ymin) y= textrct.ymin+1;
829         
830         ofs= (x-textrct.xmin)/collumwidth;
831         if(ofs<0) ofs= 0;
832         ofs*= (textrct.ymax-textrct.ymin);
833
834         return sfile->ofs+ (ofs+textrct.ymax-y)/FILESEL_DY;
835         
836 }
837
838
839 /* ********************** DRAW ******************************* */
840
841 static void calc_file_rcts(SpaceFile *sfile)
842 {
843         int tot, h, len;
844         float fac, start, totfile;
845         
846         scrollrct.xmin= 15;
847         scrollrct.xmax= 35;
848         scrollrct.ymin= 10;
849         scrollrct.ymax= curarea->winy-10-FILESELHEAD;
850         
851         textrct.xmin= scrollrct.xmax+10;
852         textrct.xmax= curarea->winx-10;
853         textrct.ymin= scrollrct.ymin;
854         textrct.ymax= scrollrct.ymax;
855         
856         if(textrct.xmax-textrct.xmin <60) textrct.xmax= textrct.xmin+60;
857         
858         len= (textrct.ymax-textrct.ymin) % FILESEL_DY;
859         textrct.ymin+= len;
860         scrollrct.ymin+= len;
861         
862         filebuty1= curarea->winy-FILESELHEAD;
863         filebuty2= filebuty1+FILESELHEAD/2 -6;
864         
865         
866         /* amount of collums */
867         len= sfile->maxnamelen+25;
868         
869         if(sfile->type==FILE_MAIN) len+= 100;
870         else if(sfile->flag & FILE_SHOWSHORT) len+= 100;
871         else len+= 380;
872         
873         sfile->collums= (textrct.xmax-textrct.xmin)/len;
874         
875         if(sfile->collums<1) sfile->collums= 1;
876         else if(sfile->collums>8) sfile->collums= 8;
877
878         /* this flag aint yet defined in user menu, needed? */
879 //      if((U.flag & USER_FSCOLLUM)==0) sfile->collums= 1;
880         
881         collumwidth= (textrct.xmax-textrct.xmin)/sfile->collums;
882         
883
884         totfile= sfile->totfile + 0.5f;
885
886         tot= (int)(FILESEL_DY*totfile);
887         if(tot) fac= ((float)sfile->collums*(scrollrct.ymax-scrollrct.ymin))/( (float)tot);
888         else fac= 1.0;
889         
890         if(sfile->ofs<0) sfile->ofs= 0;
891         
892         if(tot) start= ( (float)sfile->ofs)/(totfile);
893         else start= 0.0;
894         if(fac>1.0) fac= 1.0f;
895
896         if(start+fac>1.0) {
897                 sfile->ofs= (short)ceil((1.0-fac)*totfile);
898                 start= ( (float)sfile->ofs)/(totfile);
899                 fac= 1.0f-start;
900         }
901
902         bar.xmin= scrollrct.xmin+2;
903         bar.xmax= scrollrct.xmax-2;
904         h= (scrollrct.ymax-scrollrct.ymin)-4;
905         bar.ymax= (int)(scrollrct.ymax-2- start*h);
906         bar.ymin= (int)(bar.ymax- fac*h);
907
908         pixels_to_ofs= (totfile)/(float)(h+3);
909         page_ofs= (int)(fac*totfile);
910 }
911
912 int filescrollselect= 0;
913
914 static void draw_filescroll(SpaceFile *sfile)
915 {
916
917         if(scrollrct.ymin+10 >= scrollrct.ymax) return;
918         
919         BIF_ThemeColor(TH_BACK);
920         glRecti(scrollrct.xmin,  scrollrct.ymin,  scrollrct.xmax,  scrollrct.ymax);
921
922         uiEmboss(scrollrct.xmin, scrollrct.ymin, scrollrct.xmax, scrollrct.ymax, 1);
923
924         BIF_ThemeColor(TH_HEADER);
925         glRecti(bar.xmin+2,  bar.ymin+2,  bar.xmax-2,  bar.ymax-2);
926
927         uiEmboss(bar.xmin+2, bar.ymin+2, bar.xmax-2, bar.ymax-2, filescrollselect);
928         
929 }
930
931 static void linerect(int id, int x, int y)
932 {
933         if(id & ACTIVE) {
934                 if(id & HILITE) BIF_ThemeColorShade(TH_HILITE, 20);
935                 else BIF_ThemeColor(TH_HILITE);
936         }
937         else if(id & HILITE) BIF_ThemeColorShade(TH_BACK, 20);
938         else BIF_ThemeColor(TH_BACK);
939         
940         glRects(x-17,  y-3,  x+collumwidth-21,  y+11);
941
942 }
943
944 static void print_line(SpaceFile *sfile, struct direntry *files, int x, int y)
945 {
946         int boxcol=0;
947         char *s;
948
949         boxcol= files->flags & (HILITE + ACTIVE);
950
951         if(boxcol) {
952                 linerect(boxcol, x, y);
953         }
954
955         // this is where the little boxes in the file view are being drawn according to the file type
956         if(files->flags & BLENDERFILE) {
957                 cpack(0xA0A0);
958                 glRects(x-14,  y,  x-8,  y+7);
959         }
960         else if(files->flags & PSXFILE) {
961                 cpack(0xA060B0);
962                 glRects(x-14,  y,  x-8,  y+7);
963         }
964         else if(files->flags & IMAGEFILE) {
965                 cpack(0xF08040);
966                 glRects(x-14,  y,  x-8,  y+7);
967         }
968         else if(files->flags & MOVIEFILE) {
969                 cpack(0x70A070);
970                 glRects(x-14,  y,  x-8,  y+7);
971         }
972         else if(files->flags & PYSCRIPTFILE) {
973                 cpack(0x4477dd);
974                 glRects(x-14,  y,  x-8,  y+7);
975         }
976         else if(files->flags & SOUNDFILE) {
977                 cpack(0xa0a000);
978                 glRects(x-14,  y,  x-8,  y+7);
979         }       
980         else if(files->flags & FTFONTFILE) {
981                 cpack(0xff2371);
982                 glRects(x-14,  y,  x-8,  y+7);
983         }
984         
985         if(S_ISDIR(files->type)) BIF_ThemeColor(TH_TEXT_HI);
986         else BIF_ThemeColor(TH_TEXT);
987
988         s = files->string;
989         if(s) {
990                 glRasterPos2i(x,  y);
991                 BMF_DrawString(G.font, files->relname);
992                 
993                 x += sfile->maxnamelen + 100;
994
995                 glRasterPos2i(x - BMF_GetStringWidth(G.font, files->size),  y);
996                 BMF_DrawString(G.font, files->size);
997
998                 if(sfile->flag & FILE_SHOWSHORT) return;
999
1000 #ifndef WIN32
1001                 /* rwx rwx rwx */
1002                         x += 20; glRasterPos2i(x, y); 
1003                         BMF_DrawString(G.font, files->mode1); 
1004                 
1005                         x += 30; glRasterPos2i(x, y); 
1006                         BMF_DrawString(G.font, files->mode2); 
1007                 
1008                         x += 30; glRasterPos2i(x, y); 
1009                         BMF_DrawString(G.font, files->mode3); 
1010                 
1011                 /* owner time date */
1012                         x += 30; glRasterPos2i(x, y); 
1013                         BMF_DrawString(G.font, files->owner); 
1014 #endif
1015                 
1016                         x += 60; glRasterPos2i(x, y); 
1017                         BMF_DrawString(G.font, files->time); 
1018                 
1019                         x += 50; glRasterPos2i(x, y); 
1020                         BMF_DrawString(G.font, files->date); 
1021         }
1022         else {
1023                 glRasterPos2i(x,  y);
1024                 BMF_DrawString(G.font, files->relname);
1025                 
1026                 if(files->nr) { /* extra info */
1027                         x+= sfile->maxnamelen+20;
1028                         glRasterPos2i(x,  y);
1029                         BMF_DrawString(G.font, files->extra);
1030                 }
1031         }
1032 }
1033
1034
1035 static int calc_filesel_line(SpaceFile *sfile, int nr, int *valx, int *valy)
1036 {
1037         /* get screen coordinate of a line */
1038         int val, coll;
1039
1040         nr-= sfile->ofs;
1041
1042         /* amount of lines */
1043         val= (textrct.ymax-textrct.ymin)/FILESEL_DY;
1044         if (val == 0) coll = 0;
1045         else coll= nr/val;
1046         nr -= coll*val;
1047         
1048         *valy= textrct.ymax-FILESEL_DY+3 - nr*FILESEL_DY;
1049         *valx= coll*collumwidth + textrct.xmin+20;
1050         
1051         if(nr<0 || coll > sfile->collums) return 0;
1052         return 1;
1053 }
1054
1055 static void set_active_file(SpaceFile *sfile, int act)
1056 {
1057         struct direntry *file;
1058         int num, redraw= 0;
1059         unsigned int newflag;
1060         int old=0, newi=0;
1061         
1062         file= sfile->filelist;
1063         if(file==0) return;
1064         
1065         for(num=0; num<sfile->totfile; num++, file++) {
1066                 if(num==act) {
1067                         
1068                         if(selecting && num>1) {
1069                                 newflag= HILITE | (file->flags & ~ACTIVE);
1070                                 if(selecting==ACTIVATE) newflag |= ACTIVE;
1071                         
1072                                 if(file->flags != newflag) redraw|= 1;
1073                                 file->flags= newflag;
1074                         }
1075                         else {
1076                                 if(file->flags & HILITE);
1077                                 else {
1078                                         file->flags |= HILITE;
1079                                         redraw|= 2;
1080                                         newi= num;
1081                                 }
1082                         }
1083                 }
1084                 else {
1085                         if(file->flags & HILITE) {
1086                                 file->flags &= ~HILITE;
1087                                 redraw|= 2;
1088                                 old= num;
1089                         }
1090                 }
1091                         
1092         }
1093         // removed frontbuffer draw here
1094         if(redraw) {
1095                 scrarea_queue_winredraw(curarea);
1096         }
1097 }
1098
1099
1100 static void draw_filetext(SpaceFile *sfile)
1101 {
1102         struct direntry *files;
1103         int a, x, y;
1104         short mval[2];
1105         
1106         if(textrct.ymin+10 >= textrct.ymax) return;
1107
1108
1109         /* box */
1110         BIF_ThemeColor(TH_BACK);
1111         glRecti(textrct.xmin,  textrct.ymin,  textrct.xmax,  textrct.ymax);
1112
1113         /* collums */
1114         x= textrct.xmin+collumwidth;
1115         for(a=1; a<sfile->collums; a++, x+= collumwidth) {
1116                 cpack(0x303030);
1117                 sdrawline(x,  textrct.ymin,  x,  textrct.ymax); 
1118                 cpack(0xB0B0B0);
1119                 sdrawline(x+1,  textrct.ymin,  x+1,  textrct.ymax); 
1120         }
1121
1122         if(sfile->filelist==0) return;
1123         
1124         /* test: if mouse is not in area: clear HILITE */
1125         getmouseco_areawin(mval);
1126
1127         if(mval[0]<0 || mval[0]>curarea->winx) {
1128                 files= sfile->filelist+sfile->ofs;
1129                 for(a= sfile->ofs; a<sfile->totfile; a++, files++) files->flags &= ~HILITE;
1130         }
1131         
1132         files= sfile->filelist+sfile->ofs;
1133         for(a= sfile->ofs; a<sfile->totfile; a++, files++) {
1134         
1135                 if( calc_filesel_line(sfile, a, &x, &y)==0 ) break;
1136                 print_line(sfile, files, x, y);
1137         }
1138
1139         /* clear drawing errors, with text at the right hand side: */
1140         BIF_ThemeColor(TH_HEADER);
1141         glRecti(textrct.xmax,  textrct.ymin,  textrct.xmax+10,  textrct.ymax);
1142         uiEmboss(textrct.xmin, textrct.ymin, textrct.xmax, textrct.ymax, 1);
1143 }
1144
1145 void drawfilespace(ScrArea *sa, void *spacedata)
1146 {
1147         SpaceFile *sfile;
1148         uiBlock *block;
1149         float col[3];
1150         int act, loadbutton;
1151         short mval[2];
1152         char name[20];
1153         char *menu;
1154
1155         myortho2(-0.375, sa->winx-0.375, -0.375, sa->winy-0.375);
1156
1157         BIF_GetThemeColor3fv(TH_HEADER, col);   // basic undrawn color is border
1158         glClearColor(col[0], col[1], col[2], 0.0); 
1159         glClear(GL_COLOR_BUFFER_BIT);
1160
1161         sfile= sa->spacedata.first;     
1162         if(sfile->filelist==NULL) {
1163                 read_dir(sfile);
1164                 
1165                 calc_file_rcts(sfile);
1166                 
1167                 /* calculate act */ 
1168                 getmouseco_areawin(mval);
1169                 act= find_active_file(sfile, mval[0], mval[1]);
1170                 if(act>=0 && act<sfile->totfile)
1171                         sfile->filelist[act].flags |= HILITE;
1172         }
1173         else calc_file_rcts(sfile);
1174
1175         /* HEADER */
1176         sprintf(name, "win %d", sa->win);
1177         block= uiNewBlock(&sa->uiblocks, name, UI_EMBOSS, UI_HELV, sa->win);
1178         
1179         uiSetButLock( sfile->type==FILE_MAIN && sfile->returnfunc, NULL);
1180
1181         /* space available for load/save buttons? */
1182         loadbutton= MAX2(80, 20+BMF_GetStringWidth(G.font, sfile->title));
1183         if(textrct.xmax-textrct.xmin > loadbutton+20) {
1184                 if(sfile->title[0]==0) loadbutton= 0;
1185         }
1186         else loadbutton= 0;
1187
1188         uiDefBut(block, TEX,1,"",       textrct.xmin, filebuty1, textrct.xmax-textrct.xmin-loadbutton, 21, sfile->file, 0.0, (float)FILE_MAXFILE-1, 0, 0, "");
1189         uiDefBut(block, TEX,2,"",       textrct.xmin, filebuty2, textrct.xmax-textrct.xmin-loadbutton, 21, sfile->dir, 0.0, (float)FILE_MAXFILE-1, 0, 0, "");
1190
1191         if(loadbutton) {
1192                 uiSetCurFont(block, UI_HELV);
1193                 uiDefBut(block, BUT,        5, sfile->title,    textrct.xmax-loadbutton, filebuty2, loadbutton, 21, sfile->dir, 0.0, (float)FILE_MAXFILE-1, 0, 0, "");
1194                 uiDefBut(block, BUT,        6, "Cancel",        textrct.xmax-loadbutton, filebuty1, loadbutton, 21, sfile->file, 0.0, (float)FILE_MAXFILE-1, 0, 0, "");
1195         }
1196
1197         menu= fsmenu_build_menu();
1198         if(menu[0])     // happens when no .Bfs is there, and first time browse
1199                 uiDefButS(block, MENU,  3, menu, scrollrct.xmin, filebuty1, scrollrct.xmax-scrollrct.xmin, 21, &sfile->menu, 0, 0, 0, 0, "");
1200         MEM_freeN(menu);
1201
1202         uiDefBut(block, BUT,            4, "P", scrollrct.xmin, filebuty2, scrollrct.xmax-scrollrct.xmin, 21, 0, 0, 0, 0, 0, "Move to the parent directory (PKEY)");
1203
1204         uiDrawBlock(block);
1205
1206         draw_filescroll(sfile);
1207         draw_filetext(sfile);
1208         
1209         /* others diskfree etc ? */
1210         scrarea_queue_headredraw(sa);   
1211         
1212         myortho2(-0.375, (float)(sa->winx)-0.375, -0.375, (float)(sa->winy)-0.375);
1213         draw_area_emboss(sa);
1214         
1215         sa->win_swap= WIN_BACK_OK;
1216 }
1217
1218 static void do_filescroll(SpaceFile *sfile)
1219 {
1220         short mval[2], oldy, yo;
1221         
1222         calc_file_rcts(sfile);
1223         
1224         filescrollselect= 1;
1225         
1226         /* for beauty */
1227         scrarea_do_windraw(curarea);
1228         screen_swapbuffers();
1229         
1230         getmouseco_areawin(mval);
1231         oldy= yo= mval[1];
1232         
1233         while(get_mbut()&L_MOUSE) {
1234                 getmouseco_areawin(mval);
1235                 
1236                 if(yo!=mval[1]) {
1237                         int dy= floor(0.5+((float)(oldy-mval[1]))*pixels_to_ofs);
1238                         
1239                         if(dy) {
1240                                 sfile->ofs+= dy;
1241                                 if(sfile->ofs<0) {
1242                                         sfile->ofs= 0;
1243                                         oldy= mval[1];
1244                                 }
1245                                 else oldy= floor(0.5+ (float)oldy - (float)dy/pixels_to_ofs);
1246         
1247                                 scrarea_do_windraw(curarea);
1248                                 screen_swapbuffers();
1249         
1250                         }
1251                         
1252                         yo= mval[1];
1253                 }
1254                 else BIF_wait_for_statechange();
1255         }
1256         filescrollselect= 0;
1257
1258         /* for beauty */
1259         scrarea_do_windraw(curarea);
1260         screen_swapbuffers();
1261         
1262 }
1263
1264 static void do_filescrollwheel(SpaceFile *sfile, int move)
1265 {
1266         // by phase
1267         int lines, rt;
1268
1269         calc_file_rcts(sfile);
1270
1271         lines = (int)(textrct.ymax-textrct.ymin)/FILESEL_DY;
1272         rt = lines * sfile->collums;
1273
1274         if(sfile->totfile > rt) {
1275                 sfile->ofs+= move;
1276                 if( sfile->ofs + rt > sfile->totfile + 1)
1277                         sfile->ofs = sfile->totfile - rt + 1;
1278         }
1279
1280         if(sfile->ofs<0) {
1281                 sfile->ofs= 0;
1282         }
1283 }
1284
1285 void activate_fileselect(int type, char *title, char *file, void (*func)(char *))
1286 {
1287         SpaceFile *sfile;
1288         char group[24], name[FILE_MAXDIR], temp[FILE_MAXDIR];
1289         
1290         if(curarea==0) return;
1291         if(curarea->win==0) return;
1292         
1293         newspace(curarea, SPACE_FILE);
1294         scrarea_queue_winredraw(curarea);
1295         
1296         /* sometime double, when area already is SPACE_FILE with a different file name */
1297         if(curarea->headwin) addqueue(curarea->headwin, CHANGED, 1);
1298
1299         name[2]= 0;
1300         strcpy(name, file);
1301         
1302         sfile= curarea->spacedata.first;
1303         /* sfile wants a (*)(short), but get (*)(char*) */
1304         sfile->returnfunc= func;
1305         sfile->type= type;
1306         sfile->ofs= 0;
1307         /* sfile->act is used for databrowse: double names of library objects */
1308         sfile->act= -1;
1309         
1310         if(BLI_convertstringcode(name, G.sce, G.scene->r.cfra)) sfile->flag |= FILE_STRINGCODE;
1311         else sfile->flag &= ~FILE_STRINGCODE;
1312
1313         if (U.uiflag & USER_HIDE_DOT)
1314                 sfile->flag |= FILE_HIDE_DOT;
1315
1316         if(type==FILE_MAIN) {
1317                 char *groupname;
1318                 
1319                 strcpy(sfile->file, name+2);
1320
1321                 groupname = BLO_idcode_to_name( GS(name) );
1322                 if (groupname) {
1323                         strcpy(sfile->dir, groupname);
1324                         strcat(sfile->dir, "/");
1325                 }
1326
1327                 /* free all */
1328                 if(sfile->libfiledata) BLO_blendhandle_close(sfile->libfiledata);
1329                 sfile->libfiledata= 0;
1330                 
1331                 freefilelist(sfile);
1332         }
1333         else if(type==FILE_LOADLIB) {
1334                 strcpy(sfile->dir, name);
1335                 if( is_a_library(sfile, temp, group) ) {
1336                         /* force a reload of the library-filelist */
1337                         freefilelist(sfile);
1338                 }
1339                 else {
1340                         split_sfile(sfile, name);
1341                         if(sfile->libfiledata) BLO_blendhandle_close(sfile->libfiledata);
1342                         sfile->libfiledata= NULL;
1343                 }
1344         }
1345         else {  /* FILE_BLENDER */
1346                 split_sfile(sfile, name);       /* test filelist too */
1347                 
1348                 /* free: filelist and libfiledata became incorrect */
1349                 if(sfile->libfiledata) BLO_blendhandle_close(sfile->libfiledata);
1350                 sfile->libfiledata= 0;
1351         }
1352         BLI_strncpy(sfile->title, title, sizeof(sfile->title));
1353         filetoname= 1;
1354 }
1355
1356 void activate_imageselect(int type, char *title, char *file, void (*func)(char *))
1357 {
1358         SpaceImaSel *simasel;
1359         char dir[FILE_MAXDIR], name[FILE_MAXFILE];
1360         
1361         if(curarea==0) return;
1362         if(curarea->win==0) return;
1363         
1364         newspace(curarea, SPACE_IMASEL);
1365         
1366         /* sometimes double, when area is already SPACE_FILE with a different file name */
1367         addqueue(curarea->headwin, CHANGED, 1);
1368         addqueue(curarea->win, CHANGED, 1);
1369
1370         name[2]= 0;
1371         strcpy(name, file);
1372
1373         simasel= curarea->spacedata.first;
1374         simasel->returnfunc= func;
1375
1376         if(BLI_convertstringcode(name, G.sce, G.scene->r.cfra)) simasel->mode |= IMS_STRINGCODE;
1377         else simasel->mode &= ~IMS_STRINGCODE;
1378         
1379         BLI_split_dirfile(name, dir, simasel->file);
1380         if(strcmp(dir, simasel->dir)!=0) simasel->fase= 0;
1381         strcpy(simasel->dir, dir);
1382         
1383         BLI_strncpy(simasel->title, title, sizeof(simasel->title));
1384
1385         
1386         
1387         /* filetoname= 1; */
1388 }
1389
1390
1391 void activate_databrowse(ID *id, int idcode, int fromcode, int retval, short *menup, void (*func)(unsigned short))
1392 {
1393         ListBase *lb;
1394         SpaceFile *sfile;
1395         char str[32];
1396         
1397         if(id==0) {
1398                 lb= wich_libbase(G.main, idcode);
1399                 id= lb->last;
1400         }
1401         
1402         if(id) strcpy(str, id->name);
1403         else return;
1404         
1405         activate_fileselect(FILE_MAIN, "SELECT DATABLOCK", str, (void (*) (char*))func);
1406         
1407         sfile= curarea->spacedata.first;
1408         sfile->retval= retval;
1409         sfile->ipotype= fromcode;
1410         sfile->menup= menup;
1411 }
1412
1413 void filesel_prevspace()
1414 {
1415         SpaceFile *sfile;
1416         
1417         sfile= curarea->spacedata.first;
1418         if(sfile->next) {
1419         
1420                 BLI_remlink(&curarea->spacedata, sfile);
1421                 BLI_addtail(&curarea->spacedata, sfile);
1422
1423                 sfile= curarea->spacedata.first;
1424
1425                 if (sfile->spacetype == SPACE_SCRIPT) {
1426                         SpaceScript *sc = (SpaceScript *)sfile;
1427                         if (sc->script) sc->script->flags &=~SCRIPT_FILESEL;
1428                 }
1429
1430                 newspace(curarea, sfile->spacetype);
1431         }
1432         else newspace(curarea, SPACE_INFO);
1433 }
1434
1435 static int countselect(SpaceFile *sfile)
1436 {
1437         int a, count=0;
1438
1439         for(a=0; a<sfile->totfile; a++) {
1440                 if(sfile->filelist[a].flags & ACTIVE) {
1441                         count++;
1442                 }
1443         }
1444         return count;
1445 }
1446
1447 static int getotherdir(void)
1448 {
1449         ScrArea *sa;
1450         SpaceFile *sfile=0;
1451         
1452         sa= G.curscreen->areabase.first;
1453         while(sa) {
1454                 if(sa!=curarea) {
1455                         if(sa->spacetype==SPACE_FILE) {
1456                                 
1457                                 /* already found one */
1458                                 if(sfile) return 0;
1459                 
1460                                 sfile= sa->spacedata.first;
1461
1462                                 if(sfile->type & FILE_UNIX) {
1463                                         otherarea= sa;
1464                                         BLI_make_file_string(G.sce, otherdir, sfile->dir, "");
1465                                 }
1466                                 else sfile= 0;
1467                         }
1468                 }
1469                 sa= sa->next;
1470         }
1471         if(sfile) return 1;
1472         return 0;
1473 }
1474
1475 static void reread_other_fs(void)
1476 {
1477         SpaceFile *sfile;
1478         
1479         /* watch it: only call when getotherdir returned OK */
1480         
1481         sfile= otherarea->spacedata.first;
1482         freefilelist(sfile);
1483         scrarea_queue_winredraw(otherarea);
1484 }
1485
1486
1487 void free_filesel_spec(char *dir)
1488 {
1489         /* all filesels with 'dir' are freed */
1490         bScreen *sc;
1491                 
1492         sc= G.main->screen.first;
1493         while(sc) {
1494                 ScrArea *sa= sc->areabase.first;
1495                 while(sa) {
1496                         SpaceLink  *sl= sa->spacedata.first;
1497                         while(sl) {
1498                                 if(sl->spacetype==SPACE_FILE) {
1499                                         SpaceFile *sfile= (SpaceFile*) sl;
1500                                         if (BLI_streq(sfile->dir, dir)) {
1501                                                 freefilelist(sfile);
1502                                         }
1503                                 }
1504                                 sl= sl->next;
1505                         }
1506                         sa= sa->next;
1507                 }
1508                 sc= sc->id.next;
1509         }
1510 }
1511
1512
1513 static void filesel_execute(SpaceFile *sfile)
1514 {
1515         struct direntry *files;
1516         char name[FILE_MAXDIR];
1517         int a;
1518         
1519         filesel_prevspace();
1520
1521         if(sfile->type==FILE_LOADLIB) {
1522                 do_library_append(sfile);
1523                 BIF_undo_push("Append from file");
1524                 allqueue(REDRAWALL, 1);
1525         }
1526         else if(sfile->returnfunc) {
1527                 fsmenu_insert_entry(sfile->dir, 1);
1528         
1529                 if(sfile->type==FILE_MAIN) { /* DATABROWSE */
1530                         if (sfile->menup) {     /* with value pointing to ID block index */
1531                                 int notfound = 1;
1532
1533                                 /*      Need special handling since hiding .* datablocks means that
1534                                         sfile->act is no longer the same as files->nr.
1535
1536                                         Also, toggle HIDE_DOT on and off can make sfile->act not longer
1537                                         correct (meaning it doesn't point to the correct item in the filelist.
1538                                         
1539                                         sfile->file is always correct, so first with check if, for the item
1540                                         corresponding to sfile->act, the name is the same.
1541
1542                                         If it isn't (or if sfile->act is not good), go over filelist and take
1543                                         the correct one.
1544
1545                                         This means that selecting a datablock than hiding it makes it
1546                                         unselectable. Not really a problem.
1547
1548                                         - theeth
1549                                  */
1550
1551                                 *sfile->menup= -1;
1552
1553                                 if(sfile->act>=0) {
1554                                         if(sfile->filelist) {
1555                                                 files= sfile->filelist+sfile->act;
1556                                                 if ( strcmp(files->relname, sfile->file)==0) {
1557                                                         notfound = 0;
1558                                                         *sfile->menup= files->nr;
1559                                                 }
1560                                         }       
1561                                 }
1562                                 if (notfound) {
1563                                         for(a=0; a<sfile->totfile; a++) {
1564                                                 if( strcmp(sfile->filelist[a].relname, sfile->file)==0) {
1565                                                         *sfile->menup= sfile->filelist[a].nr;
1566                                                         break;
1567                                                 }
1568                                         }
1569                                 }
1570                         }
1571                         sfile->returnfunc((char*) (long)sfile->retval);
1572                 }
1573                 else {
1574                         if(strncmp(sfile->title, "Save", 4)==0) free_filesel_spec(sfile->dir);
1575                         if(strncmp(sfile->title, "Export", 6)==0) free_filesel_spec(sfile->dir);
1576                         
1577                         strcpy(name, sfile->dir);
1578                         strcat(name, sfile->file);
1579                         
1580                         if(sfile->flag & FILE_STRINGCODE) BLI_makestringcode(G.sce, name);
1581
1582                         sfile->returnfunc(name);
1583                 }
1584         }
1585 }
1586
1587 static void do_filesel_buttons(short event, SpaceFile *sfile)
1588 {
1589         char butname[FILE_MAXDIR];
1590         
1591         if (event == 1) {
1592                 if (strchr(sfile->file, '*') || strchr(sfile->file, '?') || strchr(sfile->file, '[')) {
1593                         int i, match = FALSE;
1594                         
1595                         for (i = 2; i < sfile->totfile; i++) {
1596                                 if (fnmatch(sfile->file, sfile->filelist[i].relname, 0) == 0) {
1597                                         sfile->filelist[i].flags |= ACTIVE;
1598                                         match = TRUE;
1599                                 }
1600                         }
1601                         if (match) strcpy(sfile->file, "");
1602                         if(sfile->type==FILE_MAIN) filesel_select_objects(sfile);
1603                         scrarea_queue_winredraw(curarea);
1604                 }
1605         }
1606         else if(event== 2) {
1607                 /* reuse the butname variable */
1608                 checkdir(sfile->dir);
1609
1610                 BLI_make_file_string(G.sce, butname, sfile->dir, "");
1611                 /* strip the trailing slash if its a real dir */
1612                 if (strlen(butname)!=1)
1613                         butname[strlen(butname)-1]=0;
1614                 
1615                 if(sfile->type & FILE_UNIX) {
1616                         if (!BLI_exists(butname)) {
1617                                 if (okee("Makedir")) {
1618                                         BLI_recurdir_fileops(butname);
1619                                         if (!BLI_exists(butname)) parent(sfile);
1620                                 } else parent(sfile);
1621                         }
1622                 }
1623                 freefilelist(sfile);
1624                 sfile->ofs= 0;
1625                 scrarea_queue_winredraw(curarea);
1626         }
1627         else if(event== 3) {
1628                 char *selected= fsmenu_get_entry(sfile->menu-1);
1629                 
1630                 /* which string */
1631                 if (selected) {
1632                         strcpy(sfile->dir, selected);
1633                         BLI_make_exist(sfile->dir);
1634                         checkdir(sfile->dir);
1635                         freefilelist(sfile);
1636                         sfile->ofs= 0;
1637                         scrarea_queue_winredraw(curarea);
1638                 }
1639
1640                 sfile->act= -1;
1641                 
1642         }
1643         else if(event== 4) parent(sfile);
1644         else if(event== 5) {
1645                 if(sfile->type) filesel_execute(sfile);
1646         }
1647         else if(event== 6) filesel_prevspace();
1648         
1649 }
1650
1651 /****/
1652
1653 typedef void (*ReplaceFP)(ID *oldblock, ID *newblock);
1654
1655 static void change_id_link(void *linkpv, void *newlinkv) {
1656         ID **linkp= (ID**) linkpv;
1657         ID *newlink= newlinkv;
1658
1659         if (*linkp) {
1660                 (*linkp)->us--;
1661         }
1662         (*linkp)= newlink;
1663         if (newlink) {
1664                 id_us_plus(newlink);
1665         }
1666 }
1667
1668 static void replace_image(ID *oldblock, ID *newblock) {
1669         Image *oldima= (Image*) oldblock;
1670         Image *newima= (Image*) newblock;
1671         bScreen *sc;
1672         Scene *sce;
1673         Tex *tex;
1674         Mesh *me;
1675
1676         for (tex= G.main->tex.first; tex; tex= tex->id.next) {
1677                 if (tex->env && tex->env->type == ENV_LOAD && tex->env->ima == oldima)
1678                         change_id_link(&tex->env->ima, newima);
1679                 if (tex->ima == oldima)
1680                         change_id_link(&tex->ima, newima);
1681         }
1682
1683         for (sce= G.main->scene.first; sce; sce= sce->id.next) {
1684                 if (sce->ima == oldima)
1685                         change_id_link(&sce->ima, newima);
1686         }
1687
1688         for (sc= G.main->screen.first; sc; sc= sc->id.next) {
1689                 ScrArea *sa;
1690
1691                 for (sa= sc->areabase.first; sa; sa= sa->next) {
1692                         SpaceLink *sl;
1693
1694                         for (sl= sa->spacedata.first; sl; sl= sl->next) {
1695                                 if (sl->spacetype == SPACE_VIEW3D) {
1696                                         View3D *v3d= (View3D*) sl;
1697                                         BGpic *bgp= v3d->bgpic;
1698
1699                                         if (bgp && bgp->ima == oldima) 
1700                                                 change_id_link(&bgp->ima, newima);
1701                                 } else if (sl->spacetype == SPACE_IMAGE) {
1702                                         SpaceImage *sima= (SpaceImage*) sl;
1703                                         
1704                                         if (sima->image == oldima)
1705                                                 change_id_link(&sima->image, newima);
1706                                 }
1707                         }
1708                 }
1709         }
1710
1711         for (me= G.main->mesh.first; me; me= me->id.next) {
1712                 TFace *tfaces= me->tface;
1713
1714                 if (tfaces) {
1715                         int i;
1716
1717                         for (i=0; i<me->totface; i++) {
1718                                 TFace *tf= &tfaces[i];
1719
1720                                 if (tf->tpage == oldima) {
1721                                                 /* not change_id_link, tpage's aren't owners :(
1722                                                  * see hack below.
1723                                                  */
1724                                         tf->tpage= newima;
1725                                 }
1726                         }
1727                 }
1728         }
1729
1730                 /* Nasty hack, necessary because tpages don't act
1731                  * as a user, so there lots of image user count
1732                  * munging occurs... this will ensure the image
1733                  * really dies.
1734                  */
1735         oldima->id.us= 0;
1736 }
1737
1738 static void replace_material(ID *oldblock, ID *newblock)
1739 {
1740         Material *old= (Material*) oldblock;
1741         Material *new= (Material*) newblock;
1742         Material ***matarar;
1743         ID *id;
1744         Object *ob;
1745         int a;
1746         
1747         ob= G.main->object.first;
1748         while(ob) {
1749                 if(ob->totcol && ob->id.lib==0) {
1750                         matarar= give_matarar(ob);
1751                         for(a=1; a<=ob->totcol; a++) {
1752                                 if(ob->mat[a-1] == old) {
1753                                         if(old) old->id.us--;
1754                                         id_us_plus((ID *)new);
1755                                         ob->mat[a-1]= new;
1756                                 }
1757                                 id= ob->data;
1758                                 if( (*matarar)[a-1] == old  && id->lib==0) {
1759                                         if(old) old->id.us--;
1760                                         id_us_plus((ID *)new);
1761                                         (*matarar)[a-1]= new;
1762                                 }
1763                         }
1764                 }
1765                 ob= ob->id.next;
1766         }
1767 }
1768
1769 static ReplaceFP get_id_replace_function(int idcode) {
1770         switch (idcode) {
1771         case ID_MA:
1772                 return &replace_material;
1773         case ID_IM:
1774                 return &replace_image;
1775         default:
1776                 return NULL;
1777         }
1778 }
1779
1780 static void databrowse_replace(SpaceFile *sfile, int idcode)
1781 {
1782         ReplaceFP replace_func= get_id_replace_function(idcode);
1783
1784         if (!replace_func) {
1785                 error("Replacing %s blocks is unsupported", BLO_idcode_to_name(idcode));
1786         } else if (sfile->act==-1) {
1787                 error("Select target with leftmouse");
1788         } else {
1789                 ID *target= (ID*) sfile->filelist[sfile->act].poin;
1790
1791                 if (target) {
1792                         char buf[128];
1793
1794                         sprintf(buf, "Replace with %s: %s", BLO_idcode_to_name(idcode), target->name+2);
1795
1796                         if (okee(buf)) {
1797                                 int i;
1798
1799                                 for (i = 0; i <sfile->totfile; i++)
1800                                         if ((sfile->filelist[i].flags&ACTIVE) && sfile->filelist[i].poin!=target)
1801                                                 replace_func(sfile->filelist[i].poin, target);
1802                         }
1803                 }
1804         }
1805
1806         freefilelist(sfile);
1807         scrarea_queue_winredraw(curarea);
1808 }
1809
1810 static void fs_fake_users(SpaceFile *sfile)
1811 {
1812         ID *id;
1813         int a;
1814         
1815         /* only for F4 DATABROWSE */
1816         if(sfile->returnfunc) return;
1817         
1818         for(a=0; a<sfile->totfile; a++) {
1819                 if(sfile->filelist[a].flags & ACTIVE) {
1820                         id= (ID *)sfile->filelist[a].poin;
1821                         if(id) {
1822                                 if( id->flag & LIB_FAKEUSER) {
1823                                         id->flag -= LIB_FAKEUSER;
1824                                         id->us--;
1825                                 }
1826                                 else {
1827                                         id->flag |= LIB_FAKEUSER;
1828                                         id->us++;
1829                                 }
1830                         }
1831                 }
1832         }
1833         freefilelist(sfile);
1834         scrarea_queue_winredraw(curarea);
1835 }
1836
1837
1838 static int get_hilited_entry(SpaceFile *sfile)
1839 {
1840         int a;
1841
1842         for(a=0; a<sfile->totfile; a++) {
1843                 if(sfile->filelist[a].flags & HILITE) {
1844                         return a;
1845                 }
1846         }
1847         return -1;
1848 }
1849
1850
1851 void winqreadfilespace(ScrArea *sa, void *spacedata, BWinEvent *evt)
1852 {
1853         unsigned short event= evt->event;
1854         short val= evt->val;
1855         static int acto=0;
1856         SpaceFile *sfile;
1857         int act, do_draw= 0, i, test, ret = 0;
1858         short qual, mval[2];
1859         char str[FILE_MAXDIR+FILE_MAXFILE+12];
1860         
1861         sfile= curarea->spacedata.first;
1862         if(sfile==0) return;
1863         if(sfile->filelist==0) {
1864                 return;
1865         }
1866         
1867         if(curarea->win==0) return;
1868         calc_file_rcts(sfile);
1869         getmouseco_areawin(mval);
1870
1871         /* prevent looping */
1872         if(selecting && !(get_mbut() & R_MOUSE)) selecting= 0;
1873
1874         if(val) {
1875
1876                 if( event!=RETKEY && event!=PADENTER)
1877                         if( uiDoBlocks(&curarea->uiblocks, event)!=UI_NOTHING ) event= 0;
1878
1879                 switch(event) {
1880                 
1881                 case UI_BUT_EVENT:
1882                         do_filesel_buttons(val, sfile);
1883                         break;          
1884                 
1885                 case WHEELDOWNMOUSE:
1886                         do_filescrollwheel(sfile, U.wheellinescroll);
1887                         act= find_active_file(sfile, mval[0], mval[1]);
1888                         set_active_file(sfile, act);
1889                         do_draw= 1;
1890                         break;
1891                 case WHEELUPMOUSE:
1892                         do_filescrollwheel(sfile, -U.wheellinescroll);
1893                         act= find_active_file(sfile, mval[0], mval[1]);
1894                         set_active_file(sfile, act);
1895                         do_draw= 1;
1896                         break;
1897
1898                 case LEFTMOUSE:
1899                 case MIDDLEMOUSE:
1900                         if(mval[0]>scrollrct.xmin && mval[0]<scrollrct.xmax && mval[1]>scrollrct.ymin && mval[1]<scrollrct.ymax) {
1901                                 do_filescroll(sfile);
1902                         }
1903                         else if(mval[0]>textrct.xmin && mval[0]<textrct.xmax && mval[1]>textrct.ymin && mval[1]<textrct.ymax) {
1904                                 
1905                                 /* sfile->act is used in databrowse: double names of library objects */
1906                                 
1907                                 sfile->act= act= find_active_file(sfile, mval[0], mval[1]);
1908                                 
1909                                 if(act>=0 && act<sfile->totfile) {
1910                                         if(S_ISDIR(sfile->filelist[act].type)) {
1911                                                 strcat(sfile->dir, sfile->filelist[act].relname);
1912                                                 strcat(sfile->dir,"/");
1913                                                 checkdir(sfile->dir);
1914                                                 freefilelist(sfile);
1915                                                 sfile->ofs= 0;
1916                                                 do_draw= 1;
1917                                         }
1918                                         else {
1919                                                 if( strcmp(sfile->file, sfile->filelist[act].relname)) {
1920                                                         do_draw= 1;
1921                                                         strcpy(sfile->file, sfile->filelist[act].relname);
1922                                                 }
1923                                                 if(event==MIDDLEMOUSE && sfile->type) filesel_execute(sfile);
1924                                         }
1925                                 }
1926                         }
1927                         break;
1928                 case RIGHTMOUSE:
1929                         act= find_active_file(sfile, mval[0], mval[1]);
1930                         acto= act;
1931                         if(act>=0 && act<sfile->totfile) {
1932
1933                                 if (sfile->filelist[act].flags & ACTIVE) {
1934                                         sfile->filelist[act].flags &= ~ACTIVE;
1935                                         selecting = INACTIVATE;
1936                                 }
1937                                 else {
1938                                         test= sfile->filelist[act].relname[0];
1939                                         if (act>=2 || test!='.') sfile->filelist[act].flags |= ACTIVE;
1940                                         
1941                                         selecting = ACTIVATE;
1942                                 }
1943                                 do_draw= 1;
1944                         }
1945                         break;
1946                 case MOUSEY:
1947                         act= find_active_file(sfile, mval[0], mval[1]);
1948                         if (act!=acto) {
1949                                 set_active_file(sfile, act);
1950                         }
1951                         if(selecting && act!=acto) {
1952                                         
1953                                 while(1) {
1954                                         if (acto >= 2 && acto < sfile->totfile) {
1955                                                 if (selecting == ACTIVATE) sfile->filelist[acto].flags |= ACTIVE;
1956                                                 else if (selecting == INACTIVATE) sfile->filelist[acto].flags &= ~ACTIVE;
1957                                         }
1958                                         if (acto < act) acto++;
1959                                         else if (acto > act) acto--;
1960                                         else break;
1961                                         
1962                                 }
1963
1964                         }
1965                         acto= act;
1966                         break;
1967                 
1968                 case PAGEUPKEY:
1969                         sfile->ofs-= page_ofs;
1970                         do_draw= 1;
1971                         break;
1972                 case PAGEDOWNKEY:
1973                         sfile->ofs+= page_ofs;
1974                         do_draw= 1;
1975                         break;
1976                 case HOMEKEY:
1977                         sfile->ofs= 0;
1978                         do_draw= 1;
1979                         break;
1980                 case ENDKEY:
1981                         sfile->ofs= sfile->totfile;
1982                         do_draw= 1;
1983                         break;
1984                 
1985                 case AKEY:
1986                         swapselect_file(sfile);
1987                         if(sfile->type==FILE_MAIN) filesel_select_objects(sfile);
1988                         do_draw= 1;
1989                         break;
1990                         
1991                 case BKEY:
1992                 case CKEY:
1993                 case LKEY:
1994                         if(event==LKEY && sfile->type==FILE_MAIN && (G.qual & LR_CTRLKEY)) {
1995                                 databrowse_replace(sfile, groupname_to_code(sfile->dir));
1996                                 break;
1997                         }
1998                         /* pass */
1999                 case MKEY:
2000                         if(sfile->type==FILE_MAIN) break;
2001
2002                         if(!countselect(sfile)) {
2003                                 error("No files selected");
2004                                 break;
2005                         }
2006                         
2007                         if(!getotherdir()) {
2008                                 error("No second fileselect");
2009                                 break;
2010                         }
2011                         
2012                         if (!strcmp(sfile->dir, otherdir)) {
2013                                 error("Same directories");
2014                                 break;
2015                         }
2016
2017                         if(event==BKEY) sprintf(str, "Backup to %s", otherdir);
2018                         else if(event==CKEY) sprintf(str, "Copy to %s", otherdir);
2019                         else if(event==LKEY) sprintf(str, "Linked copy to %s", otherdir);
2020                         else if(event==MKEY) sprintf(str, "Move to %s", otherdir);
2021                                         
2022                         if (!okee(str)) break;
2023
2024                         for (i = 0; i<sfile->totfile; i++){
2025                                 if (sfile->filelist[i].flags & ACTIVE) {                        
2026                                         BLI_make_file_string(G.sce, str, sfile->dir, sfile->filelist[i].relname);
2027
2028                                         if(event==BKEY) ret= BLI_backup(sfile->filelist[i].relname, sfile->dir, otherdir);
2029                                         else if(event==CKEY) ret= BLI_copy_fileops(str, otherdir);
2030                                         else if(event==LKEY) ret= BLI_link(str, otherdir);
2031                                         else if(event==MKEY) ret= BLI_move(str, otherdir);
2032
2033                                         if (ret) {error("Command failed, see console"); break;}
2034                                         else sfile->filelist[i].flags &= ~ACTIVE;
2035                                 }
2036                         }
2037                         do_draw= 1;
2038                         if(event==BKEY || event==MKEY) 
2039                                 freefilelist(sfile);
2040                                 
2041                         reread_other_fs();
2042                         
2043                         break;
2044
2045                 case XKEY:
2046                         test = get_hilited_entry(sfile);
2047
2048                         if (test != -1 && !(S_ISDIR(sfile->filelist[test].type))){
2049                                 BLI_make_file_string(G.sce, str, sfile->dir, sfile->filelist[test].relname);
2050
2051                                 if( okee("Remove %s", str) ) {
2052                                         ret = BLI_delete(str, 0, 0);
2053                                         if (ret) {
2054                                                 error("Command failed, see console");
2055                                         } else {
2056                                                 freefilelist(sfile);
2057                                                 do_draw= 1;
2058                                         }
2059                                 }
2060                         }
2061                         break;
2062
2063                 case RKEY:
2064                         if(sfile->type==FILE_MAIN) {
2065                                 databrowse_replace(sfile, groupname_to_code(sfile->dir));
2066                                 break;
2067                         }
2068                         /* pass to TKEY! */
2069                         
2070                 case TKEY:
2071                         if(sfile->type==FILE_MAIN) break;
2072                         
2073                         if(!countselect(sfile)) {
2074                                 error("No files selected");
2075                                 break;
2076                         }
2077
2078                         if(event==TKEY) sprintf(str, "Touch");
2079                         else if(event==RKEY) sprintf(str, "Remove from %s", sfile->dir);
2080                         
2081                         qual= G.qual;   /* because after okee() you released the SHIFT */
2082                         if (!okee(str)) break;
2083                         
2084                         for (i = 0; i <sfile->totfile; i++) {
2085                                 if (sfile->filelist[i].flags & ACTIVE) {
2086                                         BLI_make_file_string(G.sce, str, sfile->dir, sfile->filelist[i].relname);
2087
2088                                         if(event==TKEY) ret= BLI_touch(str);
2089                                         else if(event==RKEY) {
2090                                                 if(qual & LR_SHIFTKEY) ret= BLI_delete(str, 0, 1);
2091                                                 else if(S_ISDIR(sfile->filelist[i].type)) ret= BLI_delete(str, 1, 0);
2092                                                 else ret= BLI_delete(str, 0, 0);
2093                                         }
2094
2095                                         if (ret) {error("Command failed, see console"); break;}
2096                                         else sfile->filelist[i].flags &= ~ACTIVE;
2097                                 }
2098                         }
2099                         do_draw= 1;
2100                         freefilelist(sfile);
2101
2102                         break;
2103                                 
2104                 case PKEY:
2105                         if(G.qual & LR_SHIFTKEY) {
2106                                 extern char bprogname[];        /* usiblender.c */
2107                         
2108                                 sprintf(str, "%s -a \"%s%s\"", bprogname, sfile->dir, sfile->file);
2109                                 system(str);
2110                         }
2111                         else 
2112                                 parent(sfile);
2113                                 
2114                         break;
2115
2116                 case IKEY:
2117                         if(sfile->type==FILE_MAIN) break;
2118                         
2119                         sprintf(str, "$IMAGEEDITOR %s%s", sfile->dir, sfile->file);
2120                         system(str);
2121                         break;
2122                 
2123                 case EKEY:
2124                         if(sfile->type==FILE_MAIN) break;
2125                         
2126                         sprintf(str, "$WINEDITOR %s%s", sfile->dir, sfile->file);
2127                         system(str);
2128                         break;
2129                 
2130                 case FKEY:
2131                         if(sfile->type==FILE_MAIN) {
2132                                 fs_fake_users(sfile);
2133                         }
2134                         break;
2135                                 
2136                 case PADPLUSKEY:
2137                 case EQUALKEY:
2138                         if (G.qual & LR_CTRLKEY) BLI_newname(sfile->file, +100);
2139                         else if (G.qual & LR_SHIFTKEY) BLI_newname(sfile->file, +10);
2140                         else BLI_newname(sfile->file, +1);
2141                         
2142                         do_draw= 1;
2143                         break;
2144                         
2145                 case PADMINUS:
2146                 case MINUSKEY:
2147                         if (G.qual & LR_CTRLKEY) BLI_newname(sfile->file, -100);
2148                         else if (G.qual & LR_SHIFTKEY) BLI_newname(sfile->file, -10);
2149                         else BLI_newname(sfile->file, -1);
2150                         
2151                         do_draw= 1;
2152                         break;
2153                         
2154                 case BACKSLASHKEY:
2155                 case SLASHKEY:
2156                         if(sfile->type==FILE_MAIN) break;
2157
2158 #ifdef WIN32
2159                         strcpy(sfile->dir, "\\");
2160 #else
2161                         strcpy(sfile->dir, "/");
2162 #endif
2163                         freefilelist(sfile);
2164                         sfile->ofs= 0;
2165                         do_draw= 1;
2166                         break;
2167                 case PERIODKEY:
2168                         freefilelist(sfile);
2169                         do_draw= 1;
2170                         break;
2171                 case ESCKEY:
2172                         filesel_prevspace();
2173                         break;
2174                 case PADENTER:
2175                 case RETKEY:
2176                         if(sfile->type) filesel_execute(sfile);
2177                         break;
2178                 }
2179         }
2180         else if(event==RIGHTMOUSE) {
2181                 selecting = NOTACTIVE;
2182                 if(sfile->type==FILE_MAIN) filesel_select_objects(sfile);
2183         }
2184         else if(event==LEFTMOUSE) {
2185                 if(sfile->type==FILE_MAIN) active_file_object(sfile);
2186         }
2187
2188                 /* XXX, stupid patch, curarea can become undone
2189                  * because of file loading... fixme zr
2190                  */
2191         if(do_draw && curarea) scrarea_queue_winredraw(curarea);
2192 }
2193
2194
2195
2196
2197 /* ************* LIBRARY FILESEL ******************* */
2198
2199 static int groupname_to_code(char *group)
2200 {
2201         char buf[32];
2202         char *lslash;
2203         
2204         BLI_strncpy(buf, group, 31);
2205         lslash= BLI_last_slash(buf);
2206         if (lslash)
2207                 lslash[0]= '\0';
2208
2209         return BLO_idcode_from_name(buf);
2210 }
2211
2212 static int is_a_library(SpaceFile *sfile, char *dir, char *group)
2213 {
2214         /* return ok when a blenderfile, in dir is the filename,
2215          * in group the type of libdata
2216          */
2217         int len;
2218         char *fd;
2219         
2220         strcpy(dir, sfile->dir);
2221         len= strlen(dir);
2222         if(len<7) return 0;
2223         if( dir[len-1] != '/' && dir[len-1] != '\\') return 0;
2224                 
2225         group[0]= 0;
2226         dir[len-1]= 0;
2227
2228         /* Find the last slash */
2229         fd= (strrchr(dir, '/')>strrchr(dir, '\\'))?strrchr(dir, '/'):strrchr(dir, '\\');
2230
2231         if(fd==0) return 0;
2232         *fd= 0;
2233         if(BLO_has_bfile_extension(fd+1)) {
2234                 *fd= '/';
2235         }
2236         else {
2237                 strcpy(group, fd+1);
2238                         
2239                 /* Find the last slash */
2240                 fd= (strrchr(dir, '/')>strrchr(dir, '\\'))?strrchr(dir, '/'):strrchr(dir, '\\');
2241                 if (!fd || !BLO_has_bfile_extension(fd+1)) return 0;
2242         }
2243         return 1;
2244 }
2245
2246 static void do_library_append(SpaceFile *sfile)
2247 {
2248         Library *lib;
2249         char dir[FILE_MAXDIR], group[32];
2250         
2251         if ( is_a_library(sfile, dir, group)==0 ) {
2252                 error("Not a library");
2253         } else if (!sfile->libfiledata) {
2254                 error("Library not loaded");
2255         } else if (group[0]==0) {
2256                 error("Nothing indicated");
2257         } else if (BLI_streq(G.main->name, dir)) {
2258                 error("Cannot use current file as library");
2259         } else {
2260                 Object *ob;
2261                 int idcode = groupname_to_code(group);
2262                 
2263                 BLO_library_append(sfile, dir, idcode);
2264
2265                 /* DISPLISTS? */
2266                 ob= G.main->object.first;
2267                 while(ob) {
2268                         if(ob->id.lib) {
2269                                 ob->recalc |= OB_RECALC;
2270                         }
2271                         ob= ob->id.next;
2272                 }
2273         
2274                 /* in sfile->dir is the whole lib name */
2275                 strcpy(G.lib, sfile->dir);
2276                 
2277                 /* and now find the latest append lib file */
2278                 lib= G.main->library.first;
2279                 while(lib) {
2280                         if (BLI_streq(dir, lib->name)) break;
2281                         lib= lib->id.next;
2282                 }
2283                 
2284                 if((sfile->flag & FILE_LINK)==0) all_local(lib);
2285         }
2286 }
2287
2288 static void library_to_filelist(SpaceFile *sfile)
2289 {
2290         LinkNode *l, *names;
2291         int ok, i, nnames, idcode;
2292         char filename[FILE_MAXDIR+FILE_MAXFILE];
2293         char dir[FILE_MAXDIR], group[24];
2294         
2295         /* name test */
2296         ok= is_a_library(sfile, dir, group);
2297         if (!ok) {
2298                 /* free */
2299                 if(sfile->libfiledata) BLO_blendhandle_close(sfile->libfiledata);
2300                 sfile->libfiledata= 0;
2301                 return;
2302         }
2303         
2304         BLI_strncpy(filename, G.sce, sizeof(filename)); // G.sce = last file loaded, for UI
2305         
2306         /* there we go */
2307         /* for the time being only read filedata when libfiledata==0 */
2308         if (sfile->libfiledata==0) {
2309                 sfile->libfiledata= BLO_blendhandle_from_file(dir);     // this sets G.sce, we dont want it
2310                 
2311                 if(sfile->libfiledata==0) return;
2312         }
2313         
2314         idcode= groupname_to_code(group);
2315
2316                 // memory for strings is passed into filelist[i].relname
2317                 // and free'd in freefilelist
2318         if (idcode) {
2319                 names= BLO_blendhandle_get_datablock_names(sfile->libfiledata, idcode);
2320         } else {
2321                 names= BLO_blendhandle_get_linkable_groups(sfile->libfiledata);
2322         }
2323         
2324         nnames= BLI_linklist_length(names);
2325
2326         sfile->totfile= nnames + 2;
2327         sfile->filelist= malloc(sfile->totfile * sizeof(*sfile->filelist));
2328         memset(sfile->filelist, 0, sfile->totfile * sizeof(*sfile->filelist));
2329
2330         sfile->filelist[0].relname= BLI_strdup(".");
2331         sfile->filelist[0].type |= S_IFDIR;
2332         sfile->filelist[1].relname= BLI_strdup("..");
2333         sfile->filelist[1].type |= S_IFDIR;
2334                 
2335         for (i=0, l= names; i<nnames; i++, l= l->next) {
2336                 char *blockname= BLI_strdup(l->link); 
2337
2338                 sfile->filelist[i + 2].relname= blockname;
2339                 if (!idcode)
2340                         sfile->filelist[i + 2].type |= S_IFDIR;
2341         }
2342                 
2343         BLI_linklist_free(names, free);
2344         
2345         qsort(sfile->filelist, sfile->totfile, sizeof(struct direntry), compare_name);
2346         
2347         sfile->maxnamelen= 0;
2348         for(i=0; i<sfile->totfile; i++) {
2349                 int len = BMF_GetStringWidth(G.font, sfile->filelist[i].relname);
2350                 if (len > sfile->maxnamelen)
2351                         sfile->maxnamelen = len;
2352         }
2353         
2354         BLI_strncpy(G.sce, filename, sizeof(filename)); // prevent G.sce to change
2355
2356 }
2357
2358 /* ******************* DATA SELECT ********************* */
2359
2360 static void filesel_select_objects(SpaceFile *sfile)
2361 {
2362         Object *ob;
2363         Base *base;
2364         Scene *sce;
2365         int a;
2366         
2367         /* only when F4 DATABROWSE */
2368         if(sfile->returnfunc) return;
2369         
2370         if( strcmp(sfile->dir, "Object/")==0 ) {
2371                 for(a=0; a<sfile->totfile; a++) {
2372                         
2373                         ob= (Object *)sfile->filelist[a].poin;
2374                         
2375                         if(ob) {
2376                                 if(sfile->filelist[a].flags & ACTIVE) ob->flag |= SELECT;
2377                                 else ob->flag &= ~SELECT;
2378                         }
2379
2380                 }
2381                 base= FIRSTBASE;
2382                 while(base) {
2383                         base->flag= base->object->flag;
2384                         base= base->next;
2385                 }
2386                 countall();
2387                 allqueue(REDRAWVIEW3D, 0);
2388                 allqueue(REDRAWOOPS, 0);
2389         }
2390         else if( strcmp(sfile->dir, "Scene/")==0 ) {
2391                 
2392                 for(a=0; a<sfile->totfile; a++) {
2393                         
2394                         sce= (Scene *)sfile->filelist[a].poin;
2395                         if(sce) {
2396                                 if(sfile->filelist[a].flags & ACTIVE) sce->r.scemode |= R_BG_RENDER;
2397                                 else sce->r.scemode &= ~R_BG_RENDER;
2398                         }
2399
2400                 }
2401                 allqueue(REDRAWBUTSSCENE, 0);
2402         }
2403 }
2404
2405 static void active_file_object(SpaceFile *sfile)
2406 {
2407         Object *ob;
2408         
2409         /* only when F4 DATABROWSE */
2410         if(sfile->returnfunc) return;
2411         
2412         if( strcmp(sfile->dir, "Object/")==0 ) {
2413                 if(sfile->act >= 0) {
2414                         
2415                         ob= (Object *)sfile->filelist[sfile->act].poin;
2416                         
2417                         if(ob) {
2418                                 set_active_object(ob);
2419                                 if(BASACT && BASACT->object==ob) {
2420                                         BASACT->flag |= SELECT;
2421                                         sfile->filelist[sfile->act].flags |= ACTIVE;
2422                                         allqueue(REDRAWVIEW3D, 0);
2423                                         allqueue(REDRAWOOPS, 0);
2424                                         scrarea_queue_winredraw(curarea);
2425                                 }
2426                         }
2427                 }
2428         }
2429 }
2430
2431
2432 void main_to_filelist(SpaceFile *sfile)
2433 {
2434         ID *id;
2435         struct direntry *files, *firstlib = NULL;
2436         ListBase *lb;
2437         int a, fake, idcode, len, ok, totlib, totbl;
2438         short hide = 0;
2439
2440         if (sfile->flag & FILE_HIDE_DOT)
2441                 hide = 1;
2442
2443         if(sfile->dir[0]=='/') sfile->dir[0]= 0;
2444         
2445         if(sfile->dir[0]) {
2446                 idcode= groupname_to_code(sfile->dir);
2447                 if(idcode==0) sfile->dir[0]= 0;
2448         }
2449         
2450         if( sfile->dir[0]==0) {
2451                 
2452                 /* make directories */
2453                 sfile->totfile= 21;
2454                 sfile->filelist= (struct direntry *)malloc(sfile->totfile * sizeof(struct direntry));
2455                 
2456                 for(a=0; a<sfile->totfile; a++) {
2457                         memset( &(sfile->filelist[a]), 0 , sizeof(struct direntry));
2458                         sfile->filelist[a].type |= S_IFDIR;
2459                 }
2460                 
2461                 sfile->filelist[0].relname= BLI_strdup("..");
2462                 sfile->filelist[1].relname= BLI_strdup(".");
2463                 sfile->filelist[2].relname= BLI_strdup("Scene");
2464                 sfile->filelist[3].relname= BLI_strdup("Object");
2465                 sfile->filelist[4].relname= BLI_strdup("Mesh");
2466                 sfile->filelist[5].relname= BLI_strdup("Curve");
2467                 sfile->filelist[6].relname= BLI_strdup("Metaball");
2468                 sfile->filelist[7].relname= BLI_strdup("Material");
2469                 sfile->filelist[8].relname= BLI_strdup("Texture");
2470                 sfile->filelist[9].relname= BLI_strdup("Image");
2471                 sfile->filelist[10].relname= BLI_strdup("Wave");
2472                 sfile->filelist[11].relname= BLI_strdup("Lattice");
2473                 sfile->filelist[12].relname= BLI_strdup("Lamp");
2474                 sfile->filelist[13].relname= BLI_strdup("Camera");
2475                 sfile->filelist[14].relname= BLI_strdup("Ipo");
2476                 sfile->filelist[15].relname= BLI_strdup("World");
2477                 sfile->filelist[16].relname= BLI_strdup("Screen");
2478                 sfile->filelist[17].relname= BLI_strdup("VFont");
2479                 sfile->filelist[18].relname= BLI_strdup("Text");
2480                 sfile->filelist[19].relname= BLI_strdup("Armature");
2481                 sfile->filelist[20].relname= BLI_strdup("Action");
2482                 qsort(sfile->filelist, sfile->totfile, sizeof(struct direntry), compare_name);
2483         }
2484         else {
2485
2486                 /* make files */
2487                 idcode= groupname_to_code(sfile->dir);
2488                 
2489                 lb= wich_libbase(G.main, idcode );
2490                 if(lb==0) return;
2491                 
2492                 id= lb->first;
2493                 sfile->totfile= 0;
2494                 while(id) {
2495                         if(sfile->returnfunc && idcode==ID_IP) {
2496                                 if(sfile->ipotype== ((Ipo *)id)->blocktype) sfile->totfile++;
2497                         }
2498                         else if (hide==0 || id->name[2] != '.')
2499                                 sfile->totfile++;
2500
2501                         id= id->next;
2502                 }
2503                 
2504                 if(sfile->returnfunc==0) sfile->totfile+= 2;
2505                 sfile->filelist= (struct direntry *)malloc(sfile->totfile * sizeof(struct direntry));
2506                 
2507                 files= sfile->filelist;
2508                 
2509                 if(sfile->returnfunc==0) {
2510                         memset( &(sfile->filelist[0]), 0 , sizeof(struct direntry));
2511                         sfile->filelist[0].relname= BLI_strdup(".");
2512                         sfile->filelist[0].type |= S_IFDIR;
2513                         memset( &(sfile->filelist[1]), 0 , sizeof(struct direntry));
2514                         sfile->filelist[1].relname= BLI_strdup("..");
2515                         sfile->filelist[1].type |= S_IFDIR;
2516                 
2517                         files+= 2;
2518                 }
2519                 
2520                 id= lb->first;
2521                 totlib= totbl= 0;
2522                 
2523                 while(id) {
2524                         
2525                         ok= 0;
2526                         if(sfile->returnfunc && idcode==ID_IP) {
2527                                 if(sfile->ipotype== ((Ipo *)id)->blocktype) ok= 1;
2528                         }
2529                         else ok= 1;
2530                         
2531                         if(ok) {
2532                 
2533                                 if (hide==0 || id->name[2] != '.') {
2534                                         memset( files, 0 , sizeof(struct direntry));
2535                                         files->relname= BLI_strdup(id->name+2);
2536                                         
2537                                         if(sfile->returnfunc==0) { /* F4 DATA BROWSE */
2538                                                 if(idcode==ID_OB) {
2539                                                         if( ((Object *)id)->flag & SELECT) files->flags |= ACTIVE;
2540                                                 }
2541                                                 else if(idcode==ID_SCE) {
2542                                                         if( ((Scene *)id)->r.scemode & R_BG_RENDER) files->flags |= ACTIVE;
2543                                                 }
2544                                         }
2545                                         files->nr= totbl+1;
2546                                         files->poin= id;
2547                                         fake= id->flag & LIB_FAKEUSER;
2548                                         
2549                                         if(id->lib && fake) sprintf(files->extra, "LF %d", id->us);
2550                                         else if(id->lib) sprintf(files->extra, "L    %d", id->us);
2551                                         else if(fake) sprintf(files->extra, "F    %d", id->us);
2552                                         else sprintf(files->extra, "      %d", id->us);
2553                                         
2554                                         if(id->lib) {
2555                                                 if(totlib==0) firstlib= files;
2556                                                 totlib++;
2557                                         }
2558                                         
2559                                         files++;
2560                                 }
2561                                 totbl++;
2562                         }
2563                         
2564                         id= id->next;
2565                 }
2566                 
2567                 /* only qsort of libraryblokken */
2568                 if(totlib>1) {
2569                         qsort(firstlib, totlib, sizeof(struct direntry), compare_name);
2570                 }
2571         }
2572
2573         sfile->maxnamelen= 0;
2574         for(a=0; a<sfile->totfile; a++) {
2575                 len = BMF_GetStringWidth(G.font, sfile->filelist[a].relname);
2576                 if (len > sfile->maxnamelen) sfile->maxnamelen = len;
2577                 
2578                 if(filetoname) {
2579                         if( strcmp(sfile->file, sfile->filelist[a].relname)==0) {
2580                                 sfile->ofs= a-( sfile->collums*(curarea->winy-FILESELHEAD-10)/(2*FILESEL_DY));
2581                                 filetoname= 0;
2582                                 if(sfile->returnfunc) sfile->filelist[a].flags |= ACTIVE;
2583                         }
2584                 }
2585         }
2586 }
2587
2588
2589 void clever_numbuts_filesel()
2590 {
2591         SpaceFile *sfile;
2592         char orgname[FILE_MAXDIR+FILE_MAXFILE+12];
2593         char filename[FILE_MAXDIR+FILE_MAXFILE+12];
2594         char newname[FILE_MAXDIR+FILE_MAXFILE+12];
2595         int test;
2596         int len;
2597         
2598         sfile= curarea->spacedata.first;
2599
2600         if(sfile->type==FILE_MAIN) return;
2601         
2602         len = 110;
2603         test = get_hilited_entry(sfile);
2604
2605         if (test != -1 && !(S_ISDIR(sfile->filelist[test].type))){
2606                 BLI_make_file_string(G.sce, orgname, sfile->dir, sfile->filelist[test].relname);
2607                 strcpy(filename, sfile->filelist[test].relname);
2608                 
2609                 add_numbut(0, TEX, "", 0, len, filename, "Rename File");
2610
2611                 if( do_clever_numbuts("Rename File", 1, REDRAW) ) {
2612                         BLI_make_file_string(G.sce, newname, sfile->dir, filename);
2613
2614                         if( strcmp(orgname, newname) != 0 ) {
2615                                 BLI_rename(orgname, newname);
2616                                 freefilelist(sfile);
2617                         }
2618                 }
2619
2620                 scrarea_queue_winredraw(curarea);
2621         }
2622 }
2623