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