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