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