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