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