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