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