soc-2008-mxcurioni: merged changes to revision 15163
[blender-staging.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         filesel_prevspace();
1445
1446         if(sfile->type==FILE_LOADLIB) {
1447                 if(sfile->flag & FILE_STRINGCODE) {
1448                         if (!G.relbase_valid) {
1449                                 okee("You have to save the .blend file before using relative paths! Using absolute path instead.");
1450                                 sfile->flag &= ~FILE_STRINGCODE;
1451                         }
1452                 }
1453
1454                 do_library_append(sfile);
1455                 
1456                 BIF_undo_push( ((sfile->flag & FILE_LINK)==0) ? "Append from file" : "Link from file");
1457                 
1458                 allqueue(REDRAWALL, 1);
1459         }
1460         else if(filesel_has_func(sfile)) {
1461                 fsmenu_insert_entry(sfile->dir, 1, 0);
1462         
1463                 if(sfile->type==FILE_MAIN) { /* DATABROWSE */
1464                         if (sfile->menup) {     /* with value pointing to ID block index */
1465                                 int notfound = 1;
1466
1467                                 /*      Need special handling since hiding .* datablocks means that
1468                                         sfile->act is no longer the same as files->nr.
1469
1470                                         Also, toggle HIDE_DOT on and off can make sfile->act not longer
1471                                         correct (meaning it doesn't point to the correct item in the filelist.
1472                                         
1473                                         sfile->file is always correct, so first with check if, for the item
1474                                         corresponding to sfile->act, the name is the same.
1475
1476                                         If it isn't (or if sfile->act is not good), go over filelist and take
1477                                         the correct one.
1478
1479                                         This means that selecting a datablock than hiding it makes it
1480                                         unselectable. Not really a problem.
1481
1482                                         - theeth
1483                                  */
1484
1485                                 *sfile->menup= -1;
1486
1487                                 if(sfile->act>=0 && sfile->act<sfile->totfile) {
1488                                         if(sfile->filelist) {
1489                                                 files= sfile->filelist+sfile->act;
1490                                                 if ( strcmp(files->relname, sfile->file)==0) {
1491                                                         notfound = 0;
1492                                                         *sfile->menup= files->nr;
1493                                                 }
1494                                         }       
1495                                 }
1496                                 if (notfound) {
1497                                         for(a=0; a<sfile->totfile; a++) {
1498                                                 if( strcmp(sfile->filelist[a].relname, sfile->file)==0) {
1499                                                         *sfile->menup= sfile->filelist[a].nr;
1500                                                         break;
1501                                                 }
1502                                         }
1503                                 }
1504                         }
1505                         if(sfile->returnfunc_event)
1506                                 sfile->returnfunc_event(sfile->retval);
1507                         else if(sfile->returnfunc_args)
1508                                 sfile->returnfunc_args(NULL, sfile->arg1, sfile->arg2);
1509                 }
1510                 else {
1511                         if(strncmp(sfile->title, "Save", 4)==0) free_filesel_spec(sfile->dir);
1512                         if(strncmp(sfile->title, "Export", 6)==0) free_filesel_spec(sfile->dir);
1513                         
1514                         BLI_strncpy(name, sfile->dir, sizeof(name));
1515                         strcat(name, sfile->file);
1516                         
1517                         if(sfile->flag & FILE_STRINGCODE) {
1518                                 /* still weak, but we don't want saving files to make relative paths */
1519                                 if(G.relbase_valid && strncmp(sfile->title, "Save", 4)) {
1520                                         BLI_makestringcode(G.sce, name);
1521                                 } else {
1522                                         /* if we don't have a valid relative base (.blend file hasn't been saved yet)
1523                                            then we don't save the path as relative (for texture images, background image).
1524                                            Warning message not shown when saving files (doesn't make sense there)
1525                                         */
1526                                         if (strncmp(sfile->title, "Save", 4)) {
1527                                                 printf("Relative path setting has been ignored because .blend file hasn't been saved yet.\n");
1528                                         }
1529                                         sfile->flag &= ~FILE_STRINGCODE;
1530                                 }
1531                         }
1532                         if(sfile->returnfunc)
1533                                 sfile->returnfunc(name);
1534                         else if(sfile->returnfunc_args)
1535                                 sfile->returnfunc_args(name, sfile->arg1, sfile->arg2);
1536                 }
1537         }
1538 }
1539
1540 static void do_filesel_buttons(short event, SpaceFile *sfile)
1541 {
1542         char butname[FILE_MAX];
1543         
1544         if (event == B_FS_FILENAME) {
1545                 if (strchr(sfile->file, '*') || strchr(sfile->file, '?') || strchr(sfile->file, '[')) {
1546                         int i, match = FALSE;
1547                         
1548                         for (i = 2; i < sfile->totfile; i++) {
1549                                 if (fnmatch(sfile->file, sfile->filelist[i].relname, 0) == 0) {
1550                                         sfile->filelist[i].flags |= ACTIVE;
1551                                         match = TRUE;
1552                                 }
1553                         }
1554                         if (match) sfile->file[0] = '\0';
1555                         if(sfile->type==FILE_MAIN) filesel_select_objects(sfile);
1556                         scrarea_queue_winredraw(curarea);
1557                 }
1558         }
1559         else if(event== B_FS_DIRNAME) {
1560                 /* reuse the butname variable */
1561                 
1562                 /* convienence shortcut '~' -> $HOME
1563                  * If the first char is ~ then this is invalid on all OS's so its safe to replace with home */
1564                 if ( sfile->dir[0] == '~' ) {
1565                         if (sfile->dir[1] == '\0') {
1566                                 BLI_strncpy(sfile->dir, BLI_gethome(), sizeof(sfile->dir) );
1567                         } else {
1568                                 /* replace ~ with home */
1569                                 char tmpstr[FILE_MAX];
1570                                 BLI_join_dirfile(tmpstr, BLI_gethome(), sfile->dir+1);
1571                                 BLI_strncpy(sfile->dir, tmpstr, sizeof(sfile->dir));
1572                         }
1573                 }
1574                 
1575                 BLI_cleanup_dir(G.sce, sfile->dir);
1576
1577                 BLI_make_file_string(G.sce, butname, sfile->dir, "");
1578                 BLI_strncpy(sfile->dir, butname, sizeof(sfile->dir));
1579
1580                 /* strip the trailing slash if its a real dir */
1581                 BLI_del_slash(butname);
1582                 
1583                 if(sfile->type & FILE_UNIX) {
1584                         if (butname[0] != '\0' && !BLI_exists(butname)) {
1585                                 if (okee("Makedir")) {
1586                                         BLI_recurdir_fileops(butname);
1587                                         if (!BLI_exists(butname)) parent(sfile);
1588                                 } else parent(sfile);
1589                         }
1590                 }
1591                 freefilelist(sfile);
1592                 sfile->ofs= 0;
1593                 scrarea_queue_winredraw(curarea);
1594         }
1595         else if(event== B_FS_DIR_MENU) {
1596                 char *selected= fsmenu_get_entry(sfile->menu-1);
1597                 
1598                 /* which string */
1599                 if (selected) {
1600                         BLI_strncpy(sfile->dir, selected, sizeof(sfile->dir));
1601                         BLI_make_exist(sfile->dir);
1602                         BLI_cleanup_dir(G.sce, sfile->dir);
1603                         freefilelist(sfile);
1604                         sfile->ofs= 0;
1605                         scrarea_queue_winredraw(curarea);
1606                 }
1607
1608                 sfile->act= -1;
1609                 
1610         }
1611         else if(event== B_FS_PARDIR) 
1612                 parent(sfile);
1613         else if(event== B_FS_LOAD) {
1614                 if(sfile->type) 
1615                         filesel_execute(sfile);
1616         }
1617         else if(event== B_FS_CANCEL) 
1618                 filesel_prevspace();
1619         else if(event== B_FS_LIBNAME) {
1620                 Library *lib= BLI_findlink(&G.main->library, sfile->menu);
1621                 if(lib) {
1622                         BLI_strncpy(sfile->dir, lib->filename, sizeof(sfile->dir));
1623                         BLI_make_exist(sfile->dir);
1624                         BLI_cleanup_dir(G.sce, sfile->dir);
1625                         
1626                         /* forced re-reading the blend file */
1627                         if(sfile->libfiledata) BLO_blendhandle_close(sfile->libfiledata);
1628                         sfile->libfiledata= 0;
1629                         
1630                         freefilelist(sfile);
1631                         sfile->ofs= 0;
1632                         scrarea_queue_winredraw(curarea);
1633                         sfile->act= -1;
1634                 }
1635         }
1636         
1637 }
1638
1639 /****/
1640
1641 typedef void (*ReplaceFP)(ID *oldblock, ID *newblock);
1642
1643 static void change_id_link(void *linkpv, void *newlinkv) {
1644         ID **linkp= (ID**) linkpv;
1645         ID *newlink= newlinkv;
1646
1647         if (*linkp) {
1648                 (*linkp)->us--;
1649         }
1650         (*linkp)= newlink;
1651         if (newlink) {
1652                 id_us_plus(newlink);
1653         }
1654 }
1655
1656 static void replace_image(ID *oldblock, ID *newblock) {
1657         Image *oldima= (Image*) oldblock;
1658         Image *newima= (Image*) newblock;
1659         bScreen *sc;
1660         Scene *sce;
1661         Tex *tex;
1662         Mesh *me;
1663
1664         for (tex= G.main->tex.first; tex; tex= tex->id.next) {
1665                 if (tex->env && tex->env->type == ENV_LOAD && tex->env->ima == oldima)
1666                         change_id_link(&tex->env->ima, newima);
1667                 if (tex->ima == oldima)
1668                         change_id_link(&tex->ima, newima);
1669         }
1670
1671         for (sce= G.main->scene.first; sce; sce= sce->id.next) {
1672                 if (sce->ima == oldima)
1673                         change_id_link(&sce->ima, newima);
1674         }
1675
1676         for (sc= G.main->screen.first; sc; sc= sc->id.next) {
1677                 ScrArea *sa;
1678
1679                 for (sa= sc->areabase.first; sa; sa= sa->next) {
1680                         SpaceLink *sl;
1681
1682                         for (sl= sa->spacedata.first; sl; sl= sl->next) {
1683                                 if (sl->spacetype == SPACE_VIEW3D) {
1684                                         View3D *v3d= (View3D*) sl;
1685                                         BGpic *bgp= v3d->bgpic;
1686
1687                                         if (bgp && bgp->ima == oldima) 
1688                                                 change_id_link(&bgp->ima, newima);
1689                                 } else if (sl->spacetype == SPACE_IMAGE) {
1690                                         SpaceImage *sima= (SpaceImage*) sl;
1691                                         
1692                                         if (sima->image == oldima)
1693                                                 change_id_link(&sima->image, newima);
1694                                 }
1695                         }
1696                 }
1697         }
1698
1699         for (me= G.main->mesh.first; me; me= me->id.next) {
1700                 int i, a;
1701                 MTFace *tface;
1702
1703                 for(i=0; i<me->fdata.totlayer; i++) {
1704                         if(me->fdata.layers[i].type == CD_MTFACE) {
1705                                 tface= (MTFace*)me->fdata.layers[i].data;
1706
1707                                 for (a=0; a<me->totface; a++, tface++) {
1708                                         if (tface->tpage == oldima) {
1709                                                         /* not change_id_link, tpage's aren't owners :(
1710                                                          * see hack below.
1711                                                          */
1712                                                 tface->tpage= newima;
1713                                         }
1714                                 }
1715                         }
1716                 }
1717         }
1718
1719                 /* Nasty hack, necessary because tpages don't act
1720                  * as a user, so there lots of image user count
1721                  * munging occurs... this will ensure the image
1722                  * really dies.
1723                  */
1724         oldima->id.us= 0;
1725 }
1726
1727 static void replace_material(ID *oldblock, ID *newblock)
1728 {
1729         Material *old= (Material*) oldblock;
1730         Material *new= (Material*) newblock;
1731         Material ***matarar;
1732         ID *id;
1733         Object *ob;
1734         int a;
1735         
1736         ob= G.main->object.first;
1737         while(ob) {
1738                 if(ob->totcol && ob->id.lib==0) {
1739                         matarar= give_matarar(ob);
1740                         for(a=1; a<=ob->totcol; a++) {
1741                                 if(ob->mat[a-1] == old) {
1742                                         if(old) old->id.us--;
1743                                         id_us_plus((ID *)new);
1744                                         ob->mat[a-1]= new;
1745                                 }
1746                                 id= ob->data;
1747                                 if( (*matarar)[a-1] == old  && id->lib==0) {
1748                                         if(old) old->id.us--;
1749                                         id_us_plus((ID *)new);
1750                                         (*matarar)[a-1]= new;
1751                                 }
1752                         }
1753                 }
1754                 ob= ob->id.next;
1755         }
1756 }
1757
1758 static ReplaceFP get_id_replace_function(int idcode) {
1759         switch (idcode) {
1760         case ID_MA:
1761                 return &replace_material;
1762         case ID_IM:
1763                 return &replace_image;
1764         default:
1765                 return NULL;
1766         }
1767 }
1768
1769 static void databrowse_replace(SpaceFile *sfile, int idcode)
1770 {
1771         ReplaceFP replace_func= get_id_replace_function(idcode);
1772
1773         if (!replace_func) {
1774                 error("Replacing %s blocks is unsupported", BLO_idcode_to_name(idcode));
1775         } else if (sfile->act==-1) {
1776                 error("Select target with leftmouse");
1777         } else {
1778                 ID *target= (ID*) sfile->filelist[sfile->act].poin;
1779
1780                 if (target) {
1781                         char buf[128];
1782
1783                         sprintf(buf, "Replace with %s: %s", BLO_idcode_to_name(idcode), target->name+2);
1784
1785                         if (okee(buf)) {
1786                                 int i;
1787
1788                                 for (i = 0; i <sfile->totfile; i++)
1789                                         if ((sfile->filelist[i].flags&ACTIVE) && sfile->filelist[i].poin!=target)
1790                                                 replace_func(sfile->filelist[i].poin, target);
1791                         }
1792                 }
1793         }
1794
1795         freefilelist(sfile);
1796         scrarea_queue_winredraw(curarea);
1797 }
1798
1799 static void fs_fake_users(SpaceFile *sfile)
1800 {
1801         ID *id;
1802         int a;
1803         
1804         /* only for F4 DATABROWSE */
1805         if(filesel_has_func(sfile)) return;
1806         
1807         for(a=0; a<sfile->totfile; a++) {
1808                 if(sfile->filelist[a].flags & ACTIVE) {
1809                         id= (ID *)sfile->filelist[a].poin;
1810                         if(id) {
1811                                 if( id->flag & LIB_FAKEUSER) {
1812                                         id->flag -= LIB_FAKEUSER;
1813                                         id->us--;
1814                                 }
1815                                 else {
1816                                         id->flag |= LIB_FAKEUSER;
1817                                         id->us++;
1818                                 }
1819                         }
1820                 }
1821         }
1822         freefilelist(sfile);
1823         scrarea_queue_winredraw(curarea);
1824 }
1825
1826
1827 static int get_hilited_entry(SpaceFile *sfile)
1828 {
1829         int a;
1830
1831         for(a=0; a<sfile->totfile; a++) {
1832                 if(sfile->filelist[a].flags & HILITE) {
1833                         return a;
1834                 }
1835         }
1836         return -1;
1837 }
1838
1839
1840 void winqreadfilespace(ScrArea *sa, void *spacedata, BWinEvent *evt)
1841 {
1842         unsigned short event= evt->event;
1843         short val= evt->val;
1844         static int acto=0;
1845         SpaceFile *sfile;
1846         int act, do_draw= 0, i, test, ret = 0;
1847         short qual, mval[2];
1848         char str[FILE_MAX+12];
1849         
1850         sfile= curarea->spacedata.first;
1851         if(sfile==0) return;
1852         if(sfile->filelist==0) {
1853                 return;
1854         }
1855         
1856         if(curarea->win==0) return;
1857         calc_file_rcts(sfile);
1858         getmouseco_areawin(mval);
1859
1860         /* prevent looping */
1861         if(selecting && !(get_mbut() & R_MOUSE)) selecting= 0;
1862
1863         if(val) {
1864
1865                 if( event!=RETKEY && event!=PADENTER)
1866                         if( uiDoBlocks(&curarea->uiblocks, event, 1)!=UI_NOTHING ) event= 0;
1867
1868                 switch(event) {
1869                 
1870                 case UI_BUT_EVENT:
1871                         do_filesel_buttons(val, sfile);
1872                         break;          
1873                 
1874                 case WHEELDOWNMOUSE:
1875                         do_filescrollwheel(sfile, U.wheellinescroll);
1876                         act= find_active_file(sfile, mval[0], mval[1]);
1877                         set_active_file(sfile, act);
1878                         do_draw= 1;
1879                         break;
1880                 case WHEELUPMOUSE:
1881                         do_filescrollwheel(sfile, -U.wheellinescroll);
1882                         act= find_active_file(sfile, mval[0], mval[1]);
1883                         set_active_file(sfile, act);
1884                         do_draw= 1;
1885                         break;
1886
1887                 case LEFTMOUSE:
1888                 case MIDDLEMOUSE:
1889                         if(mval[0]>scrollrct.xmin && mval[0]<scrollrct.xmax && mval[1]>scrollrct.ymin && mval[1]<scrollrct.ymax) {
1890                                 do_filescroll(sfile);
1891                         }
1892                         else if(mval[0]>textrct.xmin && mval[0]<textrct.xmax && mval[1]>textrct.ymin && mval[1]<textrct.ymax) {
1893                                 
1894                                 /* sfile->act is used in databrowse: double names of library objects */
1895                                 
1896                                 sfile->act= act= find_active_file(sfile, mval[0], mval[1]);
1897                                 
1898                                 if(act>=0 && act<sfile->totfile) {
1899                                         if(S_ISDIR(sfile->filelist[act].type)) {
1900                                                 /* the path is too long and we are not going up! */
1901                                                 if (strcmp(sfile->filelist[act].relname, ".") &&
1902                                                         strcmp(sfile->filelist[act].relname, "..") &&
1903                                                         strlen(sfile->dir) + strlen(sfile->filelist[act].relname) >= FILE_MAX ) 
1904                                                 {
1905                                                         error("Path too long, cannot enter this directory");
1906                                                 } else {
1907                                                         strcat(sfile->dir, sfile->filelist[act].relname);
1908                                                         strcat(sfile->dir,"/");
1909                                                         BLI_cleanup_dir(G.sce, sfile->dir);
1910                                                         freefilelist(sfile);                                            
1911                                                         sfile->ofs= 0;
1912                                                         do_draw= 1;
1913                                                 }
1914                                         } else {
1915                                                 if( strcmp(sfile->file, sfile->filelist[act].relname)) {
1916                                                         BLI_strncpy(sfile->file, sfile->filelist[act].relname, sizeof(sfile->file));
1917                                                         do_draw = 1;
1918                                                         
1919 #ifdef INTERNATIONAL
1920                                                         if (sfile->type==FILE_LOADFONT && event!=MIDDLEMOUSE) {
1921                                                                 /* Font Preview */
1922                                                                 char tmpstr[240];
1923                                                                 if (sfile->f_fp) {
1924                                                                         sprintf (tmpstr, "%s%s", sfile->dir, sfile->file);
1925                                                                         
1926                                                                         if (!FTF_GetNewFont ((const unsigned char *)tmpstr, 0, U.fontsize)) {
1927                                                                                 error ("No font file");
1928                                                                         }
1929                                                                 }
1930                                                         }
1931 #endif
1932                                                 }
1933                                                 if(event==MIDDLEMOUSE && sfile->type) filesel_execute(sfile);
1934                                         }
1935                                 }
1936                         }
1937                         break;
1938                 case RIGHTMOUSE:
1939                         act= find_active_file(sfile, mval[0], mval[1]);
1940                         acto= act;
1941                         if(act>=0 && act<sfile->totfile) {
1942
1943                                 if (sfile->filelist[act].flags & ACTIVE) {
1944                                         sfile->filelist[act].flags &= ~ACTIVE;
1945                                         selecting = INACTIVATE;
1946                                 }
1947                                 else {
1948                                         test= sfile->filelist[act].relname[0];
1949                                         if (act>=2 || test!='.') sfile->filelist[act].flags |= ACTIVE;
1950                                         
1951                                         selecting = ACTIVATE;
1952                                 }
1953                                 do_draw= 1;
1954                         }
1955                         break;
1956                 case MOUSEY:
1957                         act= find_active_file(sfile, mval[0], mval[1]);
1958                         if (act!=acto) {
1959                                 set_active_file(sfile, act);
1960                         }
1961                         if(selecting && act!=acto) {
1962                                         
1963                                 while(1) {
1964                                         if (acto >= 2 && acto < sfile->totfile) {
1965                                                 if (selecting == ACTIVATE) sfile->filelist[acto].flags |= ACTIVE;
1966                                                 else if (selecting == INACTIVATE) sfile->filelist[acto].flags &= ~ACTIVE;
1967                                         }
1968                                         if (acto < act) acto++;
1969                                         else if (acto > act) acto--;
1970                                         else break;
1971                                         
1972                                 }
1973
1974                         }
1975                         acto= act;
1976                         break;
1977                 
1978                 case PAGEUPKEY:
1979                         sfile->ofs-= page_ofs;
1980                         do_draw= 1;
1981                         break;
1982                 case PAGEDOWNKEY:
1983                         sfile->ofs+= page_ofs;
1984                         do_draw= 1;
1985                         break;
1986                 case HOMEKEY:
1987                         sfile->ofs= 0;
1988                         do_draw= 1;
1989                         break;
1990                 case ENDKEY:
1991                         sfile->ofs= sfile->totfile;
1992                         do_draw= 1;
1993                         break;
1994                 
1995                 case AKEY:
1996                         swapselect_file(sfile);
1997                         if(sfile->type==FILE_MAIN) filesel_select_objects(sfile);
1998                         do_draw= 1;
1999                         break;
2000                         
2001                 case BKEY:
2002                 case CKEY:
2003                 case LKEY:
2004                         if(event==LKEY && sfile->type==FILE_MAIN && (G.qual & LR_CTRLKEY)) {
2005                                 databrowse_replace(sfile, groupname_to_code(sfile->dir));
2006                                 break;
2007                         }
2008                         /* pass */
2009                 case MKEY:
2010                         if(sfile->type==FILE_MAIN) break;
2011
2012                         if(!countselect(sfile)) {
2013                                 error("No files selected");
2014                                 break;
2015                         }
2016                         
2017                         if(!getotherdir()) {
2018                                 error("No second fileselect");
2019                                 break;
2020                         }
2021                         
2022                         if (!strcmp(sfile->dir, otherdir)) {
2023                                 error("Same directories");
2024                                 break;
2025                         }
2026
2027                         if(event==BKEY) sprintf(str, "Backup to %s", otherdir);
2028                         else if(event==CKEY) sprintf(str, "Copy to %s", otherdir);
2029                         else if(event==LKEY) sprintf(str, "Linked copy to %s", otherdir);
2030                         else if(event==MKEY) sprintf(str, "Move to %s", otherdir);
2031                                         
2032                         if (!okee(str)) break;
2033
2034                         for (i = 0; i<sfile->totfile; i++){
2035                                 if (sfile->filelist[i].flags & ACTIVE) {                        
2036                                         BLI_make_file_string(G.sce, str, sfile->dir, sfile->filelist[i].relname);
2037
2038                                         if(event==CKEY) ret= BLI_copy_fileops(str, otherdir);
2039                                         else if(event==LKEY) ret= BLI_link(str, otherdir);
2040                                         else if(event==MKEY) ret= BLI_move(str, otherdir);
2041
2042                                         if (ret) {error("Command failed, see console"); break;}
2043                                         else sfile->filelist[i].flags &= ~ACTIVE;
2044                                 }
2045                         }
2046                         do_draw= 1;
2047                         if(event==BKEY || event==MKEY) 
2048                                 freefilelist(sfile);
2049                                 
2050                         reread_other_fs();
2051                         
2052                         break;
2053
2054                 case XKEY:
2055                         test = get_hilited_entry(sfile);
2056
2057                         if (test != -1 && !(S_ISDIR(sfile->filelist[test].type))){
2058                                 BLI_make_file_string(G.sce, str, sfile->dir, sfile->filelist[test].relname);
2059
2060                                 if( okee("Remove %s", str) ) {
2061                                         ret = BLI_delete(str, 0, 0);
2062                                         if (ret) {
2063                                                 error("Command failed, see console");
2064                                         } else {
2065                                                 freefilelist(sfile);
2066                                                 do_draw= 1;
2067                                         }
2068                                 }
2069                         }
2070                         break;
2071
2072                 case RKEY:
2073                         if(sfile->type==FILE_MAIN) {
2074                                 databrowse_replace(sfile, groupname_to_code(sfile->dir));
2075                                 break;
2076                         }
2077                         /* pass to TKEY! */
2078                         
2079                 case TKEY:
2080                         if(sfile->type==FILE_MAIN) break;
2081                         
2082                         if(!countselect(sfile)) {
2083                                 error("No files selected");
2084                                 break;
2085                         }
2086
2087                         if(event==TKEY) sprintf(str, "Touch");
2088                         else if(event==RKEY) sprintf(str, "Remove from %s", sfile->dir);
2089                         
2090                         qual= G.qual;   /* because after okee() you released the SHIFT */
2091                         if (!okee(str)) break;
2092                         
2093                         for (i = 0; i <sfile->totfile; i++) {
2094                                 if (sfile->filelist[i].flags & ACTIVE) {
2095                                         BLI_make_file_string(G.sce, str, sfile->dir, sfile->filelist[i].relname);
2096
2097                                         if(event==TKEY) ret= BLI_touch(str);
2098                                         else if(event==RKEY) {
2099                                                 if(qual & LR_SHIFTKEY) ret= BLI_delete(str, 0, 1);
2100                                                 else if(S_ISDIR(sfile->filelist[i].type)) ret= BLI_delete(str, 1, 0);
2101                                                 else ret= BLI_delete(str, 0, 0);
2102                                         }
2103
2104                                         if (ret) {error("Command failed, see console"); break;}
2105                                         else sfile->filelist[i].flags &= ~ACTIVE;
2106                                 }
2107                         }
2108                         do_draw= 1;
2109                         freefilelist(sfile);
2110
2111                         break;
2112                                 
2113                 case PKEY:
2114                         if(G.qual & LR_SHIFTKEY) {
2115                                 extern char bprogname[];        /* usiblender.c */
2116 #ifdef WIN32                    
2117                                 sprintf(str, "%s -a \"%s%s\"", bprogname, sfile->dir, sfile->file);
2118 #else
2119                                 sprintf(str, "\"%s\" -a \"%s%s\"", bprogname, sfile->dir, sfile->file);
2120 #endif
2121                                 system(str);
2122                         }
2123                         else 
2124                                 parent(sfile);
2125                                 
2126                         break;
2127
2128                 case IKEY:
2129                         if(sfile->type==FILE_MAIN) break;
2130                         
2131                         sprintf(str, "$IMAGEEDITOR %s%s", sfile->dir, sfile->file);
2132                         system(str);
2133                         break;
2134                 
2135                 case EKEY:
2136                         if(sfile->type==FILE_MAIN) break;
2137                         
2138                         sprintf(str, "$WINEDITOR %s%s", sfile->dir, sfile->file);
2139                         system(str);
2140                         break;
2141                 
2142                 case FKEY:
2143                         if(sfile->type==FILE_MAIN) {
2144                                 fs_fake_users(sfile);
2145                         }
2146                         break;
2147                 case HKEY:
2148                         sfile->flag ^= FILE_HIDE_DOT;
2149                         BLI_hide_dot_files(sfile->flag & FILE_HIDE_DOT);
2150                         freefilelist(sfile);
2151                         scrarea_queue_winredraw(curarea);
2152                         break;
2153                 case PADPLUSKEY:
2154                 case EQUALKEY:
2155                         if (G.qual & LR_CTRLKEY) BLI_newname(sfile->file, +100);
2156                         else if (G.qual & LR_SHIFTKEY) BLI_newname(sfile->file, +10);
2157                         else BLI_newname(sfile->file, +1);
2158                         
2159                         do_draw= 1;
2160                         break;
2161                         
2162                 case PADMINUS:
2163                 case MINUSKEY:
2164                         if (G.qual & LR_CTRLKEY) BLI_newname(sfile->file, -100);
2165                         else if (G.qual & LR_SHIFTKEY) BLI_newname(sfile->file, -10);
2166                         else BLI_newname(sfile->file, -1);
2167                         
2168                         do_draw= 1;
2169                         break;
2170                         
2171                 case BACKSLASHKEY:
2172                 case SLASHKEY:
2173                         if(sfile->type==FILE_MAIN) break;
2174
2175 #ifdef WIN32
2176                         BLI_strncpy(sfile->dir, "\\", sizeof(sfile->dir));
2177 #else
2178                         BLI_strncpy(sfile->dir, "/", sizeof(sfile->dir));
2179 #endif
2180                         freefilelist(sfile);
2181                         sfile->ofs= 0;
2182                         do_draw= 1;
2183                         break;
2184                 case PERIODKEY:
2185                         freefilelist(sfile);
2186                         do_draw= 1;
2187                         break;
2188                 case ESCKEY:
2189                         filesel_prevspace();
2190                         break;
2191                 case PADENTER:
2192                 case RETKEY:
2193                         if(sfile->type) filesel_execute(sfile);
2194                         break;
2195                 }
2196         }
2197         else if(event==RIGHTMOUSE) {
2198                 selecting = NOTACTIVE;
2199                 if(sfile->type==FILE_MAIN) filesel_select_objects(sfile);
2200         }
2201         else if(event==LEFTMOUSE) {
2202                 if(sfile->type==FILE_MAIN) active_file_object(sfile);
2203         }
2204
2205                 /* XXX, stupid patch, curarea can become undone
2206                  * because of file loading... fixme zr
2207                  */
2208         if(do_draw && curarea) scrarea_queue_winredraw(curarea);
2209 }
2210
2211
2212
2213
2214 /* ************* LIBRARY FILESEL ******************* */
2215
2216 static int groupname_to_code(char *group)
2217 {
2218         char buf[GROUP_MAX];
2219         char *lslash;
2220         
2221         BLI_strncpy(buf, group, GROUP_MAX);
2222         lslash= BLI_last_slash(buf);
2223         if (lslash)
2224                 lslash[0]= '\0';
2225
2226         return BLO_idcode_from_name(buf);
2227 }
2228
2229 static int is_a_library(SpaceFile *sfile, char *dir, char *group)
2230 {
2231         /* return ok when a blenderfile, in dir is the filename,
2232          * in group the type of libdata
2233          */
2234         int len;
2235         char *fd;
2236         
2237         strcpy(dir, sfile->dir);
2238         len= strlen(dir);
2239         if(len<7) return 0;
2240         if( dir[len-1] != '/' && dir[len-1] != '\\') return 0;
2241         
2242         group[0]= 0;
2243         dir[len-1]= 0;
2244
2245         /* Find the last slash */
2246         fd= (strrchr(dir, '/')>strrchr(dir, '\\'))?strrchr(dir, '/'):strrchr(dir, '\\');
2247
2248         if(fd==0) return 0;
2249         *fd= 0;
2250         if(BLO_has_bfile_extension(fd+1)) {
2251                 /* the last part of the dir is a .blend file, no group follows */
2252                 *fd= '/'; /* put back the removed slash separating the dir and the .blend file name */
2253         }
2254         else {          
2255                 char *gp = fd+1; // in case we have a .blend file, gp points to the group
2256
2257                 /* Find the last slash */
2258                 fd= (strrchr(dir, '/')>strrchr(dir, '\\'))?strrchr(dir, '/'):strrchr(dir, '\\');
2259                 if (!fd || !BLO_has_bfile_extension(fd+1)) return 0;
2260
2261                 /* now we know that we are in a blend file and it is safe to 
2262                    assume that gp actually points to a group */
2263                 if (BLI_streq("Screen", gp)==0)
2264                         BLI_strncpy(group, gp, GROUP_MAX);
2265         }
2266         return 1;
2267 }
2268
2269 static void do_library_append(SpaceFile *sfile)
2270 {
2271         Library *lib;
2272         char dir[FILE_MAX], group[GROUP_MAX];
2273         
2274         if ( is_a_library(sfile, dir, group)==0 ) {
2275                 error("Not a library");
2276         } else if (!sfile->libfiledata) {
2277                 error("Library not loaded");
2278         } else if (group[0]==0) {
2279                 error("Nothing indicated");
2280         } else if (BLI_streq(G.main->name, dir)) {
2281                 error("Cannot use current file as library");
2282         } else {
2283                 Object *ob;
2284                 int idcode = groupname_to_code(group);
2285                 
2286                 if((sfile->flag & FILE_LINK)==0)
2287                         /* tag everything, all untagged data can be made local */
2288                         flag_all_listbases_ids(LIB_APPEND_TAG, 1);
2289                 
2290                 BLO_library_append(sfile, dir, idcode);
2291                 
2292                 /* DISPLISTS? */
2293                 ob= G.main->object.first;
2294                 while(ob) {
2295                         if(ob->id.lib) {
2296                                 ob->recalc |= OB_RECALC;
2297                         }
2298                         ob= ob->id.next;
2299                 }
2300         
2301                 /* and now find the latest append lib file */
2302                 lib= G.main->library.first;
2303                 while(lib) {
2304                         if (BLI_streq(dir, lib->filename)) break;
2305                         lib= lib->id.next;
2306                 }
2307                 
2308                 /* make local */
2309                 if(lib && (sfile->flag & FILE_LINK)==0) {
2310                         all_local(lib, 1);
2311                         /* important we unset, otherwise these object wont
2312                          * link into other scenes from this blend file */
2313                         flag_all_listbases_ids(LIB_APPEND_TAG, 0);
2314                 }
2315                 
2316                 DAG_scene_sort(G.scene);
2317                 
2318                 /* in sfile->dir is the whole lib name */
2319                 BLI_strncpy(G.lib, sfile->dir, sizeof(G.lib) );
2320         }
2321 }
2322
2323 static void library_to_filelist(SpaceFile *sfile)
2324 {
2325         LinkNode *l, *names;
2326         int ok, i, nnames, idcode;
2327         char filename[FILE_MAX];
2328         char dir[FILE_MAX], group[GROUP_MAX];
2329         
2330         /* name test */
2331         ok= is_a_library(sfile, dir, group);
2332         if (!ok) {
2333                 /* free */
2334                 if(sfile->libfiledata) BLO_blendhandle_close(sfile->libfiledata);
2335                 sfile->libfiledata= 0;
2336                 return;
2337         }
2338         
2339         BLI_strncpy(filename, G.sce, sizeof(filename)); // G.sce = last file loaded, for UI
2340         
2341         /* there we go */
2342         /* for the time being only read filedata when libfiledata==0 */
2343         if (sfile->libfiledata==0) {
2344                 sfile->libfiledata= BLO_blendhandle_from_file(dir);     // this sets G.sce, we dont want it
2345                 
2346                 if(sfile->libfiledata==0) return;
2347         }
2348         
2349         idcode= groupname_to_code(group);
2350
2351                 // memory for strings is passed into filelist[i].relname
2352                 // and free'd in freefilelist
2353         if (idcode) {
2354                 names= BLO_blendhandle_get_datablock_names(sfile->libfiledata, idcode);
2355         } else {
2356                 names= BLO_blendhandle_get_linkable_groups(sfile->libfiledata);
2357         }
2358         
2359         nnames= BLI_linklist_length(names);
2360
2361         sfile->totfile= nnames + 2;
2362         sfile->filelist= malloc(sfile->totfile * sizeof(*sfile->filelist));
2363         memset(sfile->filelist, 0, sfile->totfile * sizeof(*sfile->filelist));
2364
2365         sfile->filelist[0].relname= BLI_strdup(".");
2366         sfile->filelist[0].type |= S_IFDIR;
2367         sfile->filelist[1].relname= BLI_strdup("..");
2368         sfile->filelist[1].type |= S_IFDIR;
2369                 
2370         for (i=0, l= names; i<nnames; i++, l= l->next) {
2371                 char *blockname= BLI_strdup(l->link); 
2372
2373                 sfile->filelist[i + 2].relname= blockname;
2374                 if (!idcode)
2375                         sfile->filelist[i + 2].type |= S_IFDIR;
2376         }
2377                 
2378         BLI_linklist_free(names, free);
2379         
2380         qsort(sfile->filelist, sfile->totfile, sizeof(struct direntry), compare_name);
2381         
2382         sfile->maxnamelen= 0;
2383         for(i=0; i<sfile->totfile; i++) {
2384                 int len = BMF_GetStringWidth(G.font, sfile->filelist[i].relname);
2385                 if (len > sfile->maxnamelen)
2386                         sfile->maxnamelen = len;
2387         }
2388         
2389         BLI_strncpy(G.sce, filename, sizeof(filename)); // prevent G.sce to change
2390
2391 }
2392
2393 /* ******************* DATA SELECT ********************* */
2394
2395 static void filesel_select_objects(SpaceFile *sfile)
2396 {
2397         Object *ob;
2398         Base *base;
2399         Scene *sce;
2400         int a;
2401         
2402         /* only when F4 DATABROWSE */
2403         if(filesel_has_func(sfile)) return;
2404         
2405         if( strcmp(sfile->dir, "Object/")==0 ) {
2406                 for(a=0; a<sfile->totfile; a++) {
2407                         
2408                         ob= (Object *)sfile->filelist[a].poin;
2409                         
2410                         if(ob && (ob->flag & OB_RESTRICT_VIEW)==0) {
2411                                 if(sfile->filelist[a].flags & ACTIVE) ob->flag |= SELECT;
2412                                 else ob->flag &= ~SELECT;
2413                         }
2414
2415                 }
2416                 base= FIRSTBASE;
2417                 while(base) {
2418                         base->flag= base->object->flag;
2419                         base= base->next;
2420                 }
2421                 countall();
2422                 allqueue(REDRAWVIEW3D, 0);
2423                 allqueue(REDRAWOOPS, 0);
2424         }
2425         else if( strcmp(sfile->dir, "Scene/")==0 ) {
2426                 
2427                 for(a=0; a<sfile->totfile; a++) {
2428                         
2429                         sce= (Scene *)sfile->filelist[a].poin;
2430                         if(sce) {
2431                                 if(sfile->filelist[a].flags & ACTIVE) sce->r.scemode |= R_BG_RENDER;
2432                                 else sce->r.scemode &= ~R_BG_RENDER;
2433                         }
2434
2435                 }
2436                 allqueue(REDRAWBUTSSCENE, 0);
2437         }
2438 }
2439
2440 static void active_file_object(SpaceFile *sfile)
2441 {
2442         Object *ob;
2443         
2444         /* only when F4 DATABROWSE */
2445         if(filesel_has_func(sfile)) return;
2446         
2447         if( strcmp(sfile->dir, "Object/")==0 ) {
2448                 if(sfile->act >= 0 && sfile->act < sfile->totfile) {
2449                         
2450                         ob= (Object *)sfile->filelist[sfile->act].poin;
2451                         
2452                         if(ob && (ob->flag & OB_RESTRICT_VIEW)==0) {
2453                                 set_active_object(ob);
2454                                 if(BASACT && BASACT->object==ob) {
2455                                         BASACT->flag |= SELECT;
2456                                         sfile->filelist[sfile->act].flags |= ACTIVE;
2457                                         allqueue(REDRAWVIEW3D, 0);
2458                                         allqueue(REDRAWOOPS, 0);
2459                                         scrarea_queue_winredraw(curarea);
2460                                 }
2461                         }
2462                 }
2463         }
2464 }
2465
2466
2467 void main_to_filelist(SpaceFile *sfile)
2468 {
2469         ID *id;
2470         struct direntry *files, *firstlib = NULL;
2471         ListBase *lb;
2472         int a, fake, idcode, len, ok, totlib, totbl;
2473         short hide = 0;
2474
2475         if (sfile->flag & FILE_HIDE_DOT)
2476                 hide = 1;
2477
2478         if(sfile->dir[0]=='/') sfile->dir[0]= 0;
2479         
2480         if(sfile->dir[0]) {
2481                 idcode= groupname_to_code(sfile->dir);
2482                 if(idcode==0) sfile->dir[0]= 0;
2483         }
2484         
2485         if( sfile->dir[0]==0) {
2486                 
2487                 /* make directories */
2488                 sfile->totfile= 24;
2489                 sfile->filelist= (struct direntry *)malloc(sfile->totfile * sizeof(struct direntry));
2490                 
2491                 for(a=0; a<sfile->totfile; a++) {
2492                         memset( &(sfile->filelist[a]), 0 , sizeof(struct direntry));
2493                         sfile->filelist[a].type |= S_IFDIR;
2494                 }
2495                 
2496                 sfile->filelist[0].relname= BLI_strdup("..");
2497                 sfile->filelist[1].relname= BLI_strdup(".");
2498                 sfile->filelist[2].relname= BLI_strdup("Scene");
2499                 sfile->filelist[3].relname= BLI_strdup("Group");
2500                 sfile->filelist[4].relname= BLI_strdup("Object");
2501                 sfile->filelist[5].relname= BLI_strdup("Mesh");
2502                 sfile->filelist[6].relname= BLI_strdup("Curve");
2503                 sfile->filelist[7].relname= BLI_strdup("Metaball");
2504                 sfile->filelist[8].relname= BLI_strdup("Material");
2505                 sfile->filelist[9].relname= BLI_strdup("Texture");
2506                 sfile->filelist[10].relname= BLI_strdup("Image");
2507                 sfile->filelist[11].relname= BLI_strdup("Wave");
2508                 sfile->filelist[12].relname= BLI_strdup("Lattice");
2509                 sfile->filelist[13].relname= BLI_strdup("Lamp");
2510                 sfile->filelist[14].relname= BLI_strdup("Camera");
2511                 sfile->filelist[15].relname= BLI_strdup("Ipo");
2512                 sfile->filelist[16].relname= BLI_strdup("World");
2513                 sfile->filelist[17].relname= BLI_strdup("Screen");
2514                 sfile->filelist[18].relname= BLI_strdup("VFont");
2515                 sfile->filelist[19].relname= BLI_strdup("Text");
2516                 sfile->filelist[20].relname= BLI_strdup("Armature");
2517                 sfile->filelist[21].relname= BLI_strdup("Action");
2518                 sfile->filelist[22].relname= BLI_strdup("NodeTree");
2519                 sfile->filelist[23].relname= BLI_strdup("Brush");
2520                 
2521                 qsort(sfile->filelist, sfile->totfile, sizeof(struct direntry), compare_name);
2522         }
2523         else {
2524
2525                 /* make files */
2526                 idcode= groupname_to_code(sfile->dir);
2527                 
2528                 lb= wich_libbase(G.main, idcode );
2529                 if(lb==0) return;
2530                 
2531                 id= lb->first;
2532                 sfile->totfile= 0;
2533                 while(id) {
2534                         if(filesel_has_func(sfile) && idcode==ID_IP) {
2535                                 if(sfile->ipotype== ((Ipo *)id)->blocktype) sfile->totfile++;
2536                         }
2537                         else if (hide==0 || id->name[2] != '.')
2538                                 sfile->totfile++;
2539
2540                         id= id->next;
2541                 }
2542                 
2543                 if(!filesel_has_func(sfile)) sfile->totfile+= 2;
2544                 sfile->filelist= (struct direntry *)malloc(sfile->totfile * sizeof(struct direntry));
2545                 
2546                 files= sfile->filelist;
2547                 
2548                 if(!filesel_has_func(sfile)) {
2549                         memset( &(sfile->filelist[0]), 0 , sizeof(struct direntry));
2550                         sfile->filelist[0].relname= BLI_strdup(".");
2551                         sfile->filelist[0].type |= S_IFDIR;
2552                         memset( &(sfile->filelist[1]), 0 , sizeof(struct direntry));
2553                         sfile->filelist[1].relname= BLI_strdup("..");
2554                         sfile->filelist[1].type |= S_IFDIR;
2555                 
2556                         files+= 2;
2557                 }
2558                 
2559                 id= lb->first;
2560                 totlib= totbl= 0;
2561                 
2562                 while(id) {
2563                         
2564                         ok= 0;
2565                         if(filesel_has_func(sfile) && idcode==ID_IP) {
2566                                 if(sfile->ipotype== ((Ipo *)id)->blocktype) ok= 1;
2567                         }
2568                         else ok= 1;
2569                         
2570                         if(ok) {
2571                 
2572                                 if (hide==0 || id->name[2] != '.') {
2573                                         memset( files, 0 , sizeof(struct direntry));
2574                                         if(id->lib==NULL)
2575                                                 files->relname= BLI_strdup(id->name+2);
2576                                         else {
2577                                                 char tmp[FILE_MAX], fi[FILE_MAXFILE];
2578                                                 BLI_strncpy(tmp, id->lib->name, FILE_MAX);
2579                                                 BLI_splitdirstring(tmp, fi);
2580                                                 files->relname= MEM_mallocN(FILE_MAXFILE+32, "filename for lib");
2581                                                 sprintf(files->relname, "%s / %s", fi, id->name+2);
2582                                         }
2583                                         
2584                                         if(!filesel_has_func(sfile)) { /* F4 DATA BROWSE */
2585                                                 if(idcode==ID_OB) {
2586                                                         if( ((Object *)id)->flag & SELECT) files->flags |= ACTIVE;
2587                                                 }
2588                                                 else if(idcode==ID_SCE) {
2589                                                         if( ((Scene *)id)->r.scemode & R_BG_RENDER) files->flags |= ACTIVE;
2590                                                 }
2591                                         }
2592                                         files->nr= totbl+1;
2593                                         files->poin= id;
2594                                         fake= id->flag & LIB_FAKEUSER;
2595                                         
2596                                         if(id->lib && fake) sprintf(files->extra, "LF %d", id->us);
2597                                         else if(id->lib) sprintf(files->extra, "L    %d", id->us);
2598                                         else if(fake) sprintf(files->extra, "F    %d", id->us);
2599                                         else sprintf(files->extra, "      %d", id->us);
2600                                         
2601                                         if(id->lib) {
2602                                                 if(totlib==0) firstlib= files;
2603                                                 totlib++;
2604                                         }
2605                                         
2606                                         files++;
2607                                 }
2608                                 totbl++;
2609                         }
2610                         
2611                         id= id->next;
2612                 }
2613                 
2614                 /* only qsort of libraryblokken */
2615                 if(totlib>1) {
2616                         qsort(firstlib, totlib, sizeof(struct direntry), compare_name);
2617                 }
2618         }
2619
2620         sfile->maxnamelen= 0;
2621         for(a=0; a<sfile->totfile; a++) {
2622                 len = BMF_GetStringWidth(G.font, sfile->filelist[a].relname);
2623                 if (len > sfile->maxnamelen) sfile->maxnamelen = len;
2624                 
2625                 if(filetoname) {
2626                         if( strcmp(sfile->file, sfile->filelist[a].relname)==0) {
2627                                 sfile->ofs= a-( sfile->collums*(curarea->winy-FILESELHEAD-10)/(2*FILESEL_DY));
2628                                 filetoname= 0;
2629                                 if(filesel_has_func(sfile)) sfile->filelist[a].flags |= ACTIVE;
2630                         }
2631                 }
2632         }
2633 }
2634
2635
2636 void clever_numbuts_filesel()
2637 {
2638         SpaceFile *sfile;
2639         char orgname[FILE_MAX+12];
2640         char filename[FILE_MAX+12];
2641         char newname[FILE_MAX+12];
2642         int test;
2643         int len;
2644         
2645         sfile= curarea->spacedata.first;
2646
2647         if(sfile->type==FILE_MAIN) return;
2648         
2649         len = 110;
2650         test = get_hilited_entry(sfile);
2651
2652         if (test != -1 && !(S_ISDIR(sfile->filelist[test].type))){
2653                 BLI_make_file_string(G.sce, orgname, sfile->dir, sfile->filelist[test].relname);
2654                 BLI_strncpy(filename, sfile->filelist[test].relname, sizeof(filename));
2655                 
2656                 add_numbut(0, TEX, "", 0, len, filename, "Rename File");
2657
2658                 if( do_clever_numbuts("Rename File", 1, REDRAW) ) {
2659                         BLI_make_file_string(G.sce, newname, sfile->dir, filename);
2660
2661                         if( strcmp(orgname, newname) != 0 ) {
2662                                 BLI_rename(orgname, newname);
2663                                 freefilelist(sfile);
2664                         }
2665                 }
2666
2667                 scrarea_queue_winredraw(curarea);
2668         }
2669 }
2670