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