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