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