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