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