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