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