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