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