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