== ImageBrowser ==
[blender.git] / source / blender / src / editimasel.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 <stdio.h>
36 #include <math.h>
37
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41
42 #ifndef WIN32
43 #include <sys/times.h>
44 #endif
45
46 #include "MEM_guardedalloc.h"
47
48 #include "BKE_global.h"
49 #include "BKE_library.h"
50 #include "BKE_main.h"
51 #include "BKE_depsgraph.h"
52 #include "BKE_utildefines.h"
53
54 #include "BLI_blenlib.h"
55 #include "BLI_arithb.h"
56 #include "BLI_storage_types.h"
57
58 #ifdef WIN32
59 #include "BLI_winstuff.h"
60 #endif
61
62 #include "DNA_armature_types.h"
63 #include "DNA_action_types.h"
64 #include "DNA_curve_types.h"
65 #include "DNA_image_types.h"
66 #include "DNA_ipo_types.h"
67 #include "DNA_material_types.h"
68 #include "DNA_mesh_types.h"
69 #include "DNA_object_types.h"
70 #include "DNA_texture_types.h"
71 #include "DNA_space_types.h"
72 #include "DNA_scene_types.h"
73 #include "DNA_screen_types.h"
74 #include "DNA_userdef_types.h"
75 #include "DNA_vfont_types.h"
76 #include "DNA_view3d_types.h"
77
78
79 #include "BIF_filelist.h"
80 #include "BIF_space.h"
81 #include "BIF_screen.h"
82 #include "BIF_interface.h"
83 #include "BIF_mywindow.h"
84 #include "BIF_imasel.h"
85 #include "BIF_gl.h"
86 #include "BIF_fsmenu.h"
87 #include "BIF_editview.h"
88 #include "BIF_toolbox.h"
89
90 #include "BLO_readfile.h"
91
92 #include "BPI_script.h"
93
94 #include "BSE_drawipo.h"
95 #include "BSE_drawimasel.h"
96 #include "BSE_edit.h"
97
98 #include "IMB_imbuf.h"
99 #include "IMB_imbuf_types.h"
100
101 #include "blendef.h"
102 #include "mydevice.h"
103
104 /* for events */
105 #define NOTACTIVE                       0
106 #define ACTIVATE                        1
107 #define INACTIVATE                      2
108 /* for state of file */
109 #define ACTIVE                          2
110
111 static void imasel_select_objects(SpaceImaSel *simasel);
112
113 static int imasel_has_func(SpaceImaSel *simasel)
114 {
115         if(simasel->returnfunc || simasel->returnfunc_event || simasel->returnfunc_args)
116                 return 1;
117         return 0;
118 }
119
120 #if defined __BeOS
121 static int fnmatch(const char *pattern, const char *string, int flags)
122 {
123         return 0;
124 }
125 #elif defined WIN32 && !defined _LIBC
126         /* use fnmatch included in blenlib */
127         #include "BLI_fnmatch.h"
128 #else
129         #include <fnmatch.h>
130 #endif
131
132 static void imasel_split_file(SpaceImaSel *simasel, char *s1)
133 {
134         char string[FILE_MAX], dir[FILE_MAX], file[FILE_MAX];
135
136         BLI_strncpy(string, s1, sizeof(string));
137
138         BLI_split_dirfile(string, dir, file);
139         
140         if(simasel->files) {
141                 BIF_filelist_free(simasel->files);
142         }
143         BLI_strncpy(simasel->file, file, sizeof(simasel->file));
144         BLI_strncpy(simasel->dir, dir, sizeof(simasel->dir));
145
146         BIF_filelist_setdir(simasel->files, dir);
147
148         BLI_make_file_string(G.sce, simasel->dir, dir, "");
149 }
150
151 /**************** IMAGESELECT ******************************/
152
153 /* the complete call; pulldown menu, and three callback types */
154 static void activate_imageselect_(int type, char *title, char *file, short *menup, char *pupmenu,
155                                                                                  void (*func)(char *),
156                                                                                  void (*func_event)(unsigned short),
157                                                                                  void (*func_args)(char *, void *arg1, void *arg2),
158                                                                                  void *arg1, void *arg2)
159 {
160         SpaceImaSel *simasel;
161         char group[24], name[FILE_MAX], temp[FILE_MAX];
162         
163         if(curarea==0) return;
164         if(curarea->win==0) return;
165         
166         newspace(curarea, SPACE_IMASEL);
167         scrarea_queue_winredraw(curarea);
168         
169         /* sometime double, when area already is SPACE_IMASEL with a different file name */
170         if(curarea->headwin) addqueue(curarea->headwin, CHANGED, 1);
171
172         name[2]= 0;
173         BLI_strncpy(name, file, sizeof(name));
174         BLI_convertstringcode(name, G.sce, G.scene->r.cfra);
175         
176         
177         simasel= curarea->spacedata.first;
178
179         simasel->returnfunc= func;
180         simasel->returnfunc_event= func_event;
181         simasel->returnfunc_args= func_args;
182         simasel->arg1= arg1;
183         simasel->arg2= arg2;
184         
185         simasel->type= type;
186         simasel->scrollpos = 0.0f;
187
188         if(simasel->pupmenu)
189                 MEM_freeN(simasel->pupmenu);
190         simasel->pupmenu= pupmenu;
191         simasel->menup= menup;
192         
193         /* sfile->act is used for databrowse: double names of library objects */
194         simasel->active_file= -1;
195
196         if(!simasel->files) {
197                 simasel->files = BIF_filelist_new();
198         }
199
200         if(G.relbase_valid && U.flag & USER_RELPATHS && type != FILE_BLENDER)
201                 simasel->flag |= FILE_STRINGCODE;
202         else
203                 simasel->flag &= ~FILE_STRINGCODE;
204
205         if (U.uiflag & USER_HIDE_DOT)
206                 simasel->flag |= FILE_HIDE_DOT;
207
208         if(type==FILE_MAIN) {
209                 char *groupname;
210                 
211                 BLI_strncpy(simasel->file, name+2, sizeof(simasel->file));
212
213                 groupname = BLO_idcode_to_name( GS(name) );
214                 if (groupname) {
215                         BLI_strncpy(simasel->dir, groupname, sizeof(simasel->dir) - 1);
216                         strcat(simasel->dir, "/");
217                 }
218
219                 /* free all */
220                 if (simasel->files) {
221                         BIF_filelist_freelib(simasel->files);                           
222                         BIF_filelist_free(simasel->files);
223                         BIF_filelist_setdir(simasel->files, simasel->dir);
224                         BIF_filelist_settype(simasel->files, type);
225                 }
226         }
227         else if(type==FILE_LOADLIB) {
228                 
229                 if( BIF_filelist_islibrary(simasel->files, temp, group) ) {
230                         /* force a reload of the library-filelist */
231                         BIF_filelist_free(simasel->files);
232                         BIF_filelist_freelib(simasel->files);
233                         BLI_strncpy(simasel->dir, name, sizeof(simasel->dir));
234                         BIF_filelist_setdir(simasel->files, simasel->dir);
235                         BIF_filelist_settype(simasel->files, type);
236                 }
237                 else {
238                         imasel_split_file(simasel, name);
239                         BIF_filelist_freelib(simasel->files);
240                         BIF_filelist_settype(simasel->files, type);                     
241                 }
242         }
243         else {  /* FILE_BLENDER */
244                 imasel_split_file(simasel, name);
245                 BIF_filelist_settype(simasel->files, type);
246
247                 BLI_cleanup_dir(G.sce, simasel->dir);
248
249                 /* free: filelist and libfiledata became incorrect */
250                 BIF_filelist_freelib(simasel->files);
251         }
252         BLI_strncpy(simasel->title, title, sizeof(simasel->title));
253         /* filetoname= 1; */ /* TODO: elubie - check what this means */
254 }
255
256 void activate_imageselect(int type, char *title, char *file, void (*func)(char *))
257 {
258         activate_imageselect_(type, title, file, NULL, NULL, func, NULL, NULL, NULL, NULL);
259 }
260
261 void activate_imageselect_menu(int type, char *title, char *file, char *pupmenu, short *menup, void (*func)(char *))
262 {
263         activate_imageselect_(type, title, file, menup, pupmenu, func, NULL, NULL, NULL, NULL);
264 }
265
266 void activate_imageselect_args(int type, char *title, char *file, void (*func)(char *, void *, void *), void *arg1, void *arg2)
267 {
268         activate_imageselect_(type, title, file, NULL, NULL, NULL, NULL, func, arg1, arg2);
269 }
270
271 void activate_databrowse_imasel(ID *id, int idcode, int fromcode, int retval, short *menup, void (*func)(unsigned short))
272 {
273         ListBase *lb;
274         SpaceImaSel *simasel;
275         char str[32];
276         
277         if(id==NULL) {
278                 lb= wich_libbase(G.main, idcode);
279                 id= lb->first;
280         }
281         
282         if(id) BLI_strncpy(str, id->name, sizeof(str));
283         else return;
284
285         activate_imageselect_(FILE_MAIN, "SELECT DATABLOCK", str, menup, NULL, NULL, func, NULL, NULL, NULL);
286         
287         simasel= curarea->spacedata.first;
288         simasel->retval= retval;
289         simasel->menup= menup;
290
291         BIF_filelist_setipotype(simasel->files, fromcode);
292         BIF_filelist_hasfunc(simasel->files, imasel_has_func(simasel));
293 }
294
295
296 static void set_active_file(SpaceImaSel *simasel, short x, short y)
297 {
298         short tilex, tiley;
299         int active_tile;
300         int active_file;
301         int stridex;
302         struct direntry* file;
303         rcti viewrect = simasel->viewrect;
304         int fileoffset;
305         int rowoffset;
306         int rowleftover;
307         float scrollofs;
308         int numfiles;
309         int tilewidth = simasel->prv_w + TILE_BORDER_X*4;
310         int tileheight = simasel->prv_h + TILE_BORDER_Y*4 + U.fontsize;
311
312         numfiles = BIF_filelist_numfiles(simasel->files);
313         
314         if (simasel->numtilesx > 0) {
315                 fileoffset = numfiles*(simasel->scrollpos / simasel->scrollarea) + 0.5;
316                 rowoffset = (fileoffset / simasel->numtilesx)*simasel->numtilesx;
317                 rowleftover = fileoffset % simasel->numtilesx;
318                 scrollofs = (float)tileheight*(float)rowleftover/(float)simasel->numtilesx;
319         
320                 stridex = (viewrect.xmax - viewrect.xmin) / (tilewidth);
321                 tilex = ( (x-viewrect.xmin)) / (tilewidth);
322                 tiley = (viewrect.ymax - viewrect.ymin + scrollofs - y) / (tileheight);
323                 if (tilex >= simasel->numtilesx) tilex = simasel->numtilesx-1;
324                 if (tiley >= simasel->numtilesy+1) tiley = simasel->numtilesy;
325                 if (tilex < 0) tilex=0;
326                 if (tiley < 0) tiley = 0;
327                 active_tile = tilex + stridex*tiley;
328                 active_file = rowoffset + active_tile;
329
330                 if (active_file >= 0 && active_file < BIF_filelist_numfiles(simasel->files) )
331                 {
332                         simasel->active_file = active_file;
333                         if (simasel->selstate & ACTIVATE) {
334                                 file = BIF_filelist_file(simasel->files, simasel->active_file);
335                                 file->flags |= ACTIVE;
336                         }
337                 } else {
338                         simasel->active_file = -1;
339                 }
340         } else {
341                 simasel->active_file = -1;
342         }
343 }
344
345 static void set_active_bookmark(SpaceImaSel *simasel, short y)
346 {
347         int nentries = fsmenu_get_nentries();
348         short posy = simasel->bookmarkrect.ymax - TILE_BORDER_Y - y;
349         simasel->active_bookmark = ((float)posy / (U.fontsize*3.0f/2.0f));      
350         if (simasel->active_bookmark < 0 || simasel->active_bookmark > nentries) {
351                 simasel->active_bookmark = -1;
352         }
353 }
354
355 static void imasel_prevspace()
356 {
357         SpaceImaSel *simasel;   
358
359         simasel= curarea->spacedata.first;
360
361         /* cleanup */
362         if(simasel->spacetype==SPACE_IMASEL) {
363                 if(simasel->pupmenu) {
364                         MEM_freeN(simasel->pupmenu);
365                         simasel->pupmenu= NULL;
366                 }
367         }
368
369         if(simasel->next) {
370         
371                 BLI_remlink(&curarea->spacedata, simasel);
372                 BLI_addtail(&curarea->spacedata, simasel);
373
374                 simasel= curarea->spacedata.first;
375
376                 if (simasel->spacetype == SPACE_SCRIPT) {
377                         SpaceScript *sc = (SpaceScript *)simasel;
378                         if (sc->script) sc->script->flags &=~SCRIPT_FILESEL;
379                 }
380
381                 newspace(curarea, simasel->spacetype);
382         }
383         else newspace(curarea, SPACE_INFO);
384 }
385
386 static void free_imasel_spec(char *dir)
387 {
388         /* all filesels with 'dir' are freed */
389         bScreen *sc;
390                 
391         sc= G.main->screen.first;
392         while(sc) {
393                 ScrArea *sa= sc->areabase.first;
394                 while(sa) {
395                         SpaceLink  *sl= sa->spacedata.first;
396                         while(sl) {
397                                 if(sl->spacetype==SPACE_FILE) {
398                                         SpaceImaSel *simasel= (SpaceImaSel*) sl;
399                                         if (BLI_streq(simasel->dir, dir)) {
400                                                 BIF_filelist_free(simasel->files);
401                                         }
402                                 }
403                                 sl= sl->next;
404                         }
405                         sa= sa->next;
406                 }
407                 sc= sc->id.next;
408         }
409 }
410
411 static void do_library_append(SpaceImaSel *simasel)
412 {
413         Library *lib;
414         char dir[FILE_MAXDIR], group[32];
415         
416         if ( BIF_filelist_islibrary(simasel->files, dir, group)==0 ) {
417                 error("Not a library");
418         } else if (!BIF_filelist_lib(simasel->files) ) {
419                 error("Library not loaded");
420         } else if (group[0]==0) {
421                 error("Nothing indicated");
422         } else if (BLI_streq(G.main->name, dir)) {
423                 error("Cannot use current file as library");
424         } else {
425                 Object *ob;
426                 int idcode = BIF_groupname_to_code(group);
427                                 
428                 if((simasel->flag & FILE_LINK)==0) {
429                         /* tag everything, all untagged data can be made local */
430                         ID *id;
431                         ListBase *lbarray[MAX_LIBARRAY];
432                         int a;
433                         
434                         a= set_listbasepointers(G.main, lbarray);
435                         while(a--) {
436                                 for(id= lbarray[a]->first; id; id= id->next) id->flag |= LIB_APPEND_TAG;
437                         }
438                 }
439
440                 BIF_filelist_append_library(simasel->files, dir, simasel->file, simasel->flag, idcode);
441
442                 /* DISPLISTS? */
443                 ob= G.main->object.first;
444                 while(ob) {
445                         if(ob->id.lib) {
446                                 ob->recalc |= OB_RECALC;
447                         }
448                         ob= ob->id.next;
449                 }
450         
451                 /* and now find the latest append lib file */
452                 lib= G.main->library.first;
453                 while(lib) {
454                         if (BLI_streq(dir, lib->filename)) break;
455                         lib= lib->id.next;
456                 }
457                 
458                 /* make local */
459                 if(lib) {
460                         if((simasel->flag & FILE_LINK)==0) 
461                                 all_local(lib,1);
462                 }
463                 
464                 DAG_scene_sort(G.scene);
465
466                 /* in sfile->dir is the whole lib name */
467                 BLI_strncpy(G.lib, simasel->dir, sizeof(G.lib) );
468                 
469         }
470 }
471
472 /* NOTE: this is called for file read, after the execfunc no UI memory is valid! */
473 static void imasel_execute(SpaceImaSel *simasel)
474 {
475         struct direntry *file;
476         char name[FILE_MAX];
477         int a;
478         int n;
479         
480         imasel_prevspace();
481
482         if(simasel->type==FILE_LOADLIB) {
483                 if(simasel->flag & FILE_STRINGCODE) {
484                         if (!G.relbase_valid) {
485                                 okee("You have to save the .blend file before using relative paths! Using absolute path instead.");
486                                 simasel->flag &= ~FILE_STRINGCODE;
487                         }
488                 }
489
490                 do_library_append(simasel);
491                 BIF_undo_push("Append from file");
492                 allqueue(REDRAWALL, 1);
493         }
494         else if(imasel_has_func(simasel)) {
495                 fsmenu_insert_entry(simasel->dir, 1, 0);
496         
497                 if(simasel->type==FILE_MAIN) { /* DATABROWSE */
498                         if (simasel->menup) {   /* with value pointing to ID block index */
499                                 int notfound = 1;
500
501                                 /*      Need special handling since hiding .* datablocks means that
502                                         simasel->active_file is no longer the same as files->nr.
503
504                                         Also, toggle HIDE_DOT on and off can make simasel->active_file not longer
505                                         correct (meaning it doesn't point to the correct item in the filelist.
506                                         
507                                         simasel->file is always correct, so first with check if, for the item
508                                         corresponding to simasel->active_file, the name is the same.
509
510                                         If it isn't (or if simasel->active_file is not good), go over filelist and take
511                                         the correct one.
512
513                                         This means that selecting a datablock than hiding it makes it
514                                         unselectable. Not really a problem.
515
516                                         - theeth
517                                  */
518
519                                 *simasel->menup= -1;
520                                 n = BIF_filelist_numfiles(simasel->files);
521                                 if(simasel->files) {
522                                         if( (simasel->active_file>=0) && (simasel->active_file < n) ) {
523                                                 file = BIF_filelist_file(simasel->files, simasel->active_file);                                         
524                                                 if ( strcmp(file->relname, simasel->file)==0) {
525                                                         notfound = 0;
526                                                         *simasel->menup= file->nr;
527                                                 }
528                                         }
529                                         if (notfound) {                                 
530                                                 for(a=0; a<n; a++) {
531                                                         file = BIF_filelist_file(simasel->files, a);    
532                                                         if( strcmp(file->relname, simasel->file)==0) {
533                                                                 *simasel->menup= file->nr;
534                                                                 break;
535                                                         }
536                                                 }
537                                         }
538                                 }
539                         }
540                         if(simasel->returnfunc_event)
541                                 simasel->returnfunc_event(simasel->retval);
542                         else if(simasel->returnfunc_args)
543                                 simasel->returnfunc_args(NULL, simasel->arg1, simasel->arg2);
544                 }
545                 else {
546                         if(strncmp(simasel->title, "Save", 4)==0) free_imasel_spec(simasel->dir);
547                         if(strncmp(simasel->title, "Export", 6)==0) free_imasel_spec(simasel->dir);
548                         
549                         BLI_strncpy(name, simasel->dir, sizeof(name));
550                         strcat(name, simasel->file);
551                         
552                         if(simasel->flag & FILE_STRINGCODE) {
553                                 /* still weak, but we don't want saving files to make relative paths */
554                                 if(G.relbase_valid && strncmp(simasel->title, "Save", 4)) {
555                                         BLI_makestringcode(G.sce, name);
556                                 } else {
557                                         /* if we don't have a valid relative base (.blend file hasn't been saved yet)
558                                            then we don't save the path as relative (for texture images, background image).      
559                                            Warning message not shown when saving files (doesn't make sense there)
560                                         */
561                                         if (strncmp(simasel->title, "Save", 4)) {                                       
562                                                 printf("Relative path setting has been ignored because .blend file hasn't been saved yet.\n");
563                                         }
564                                         simasel->flag &= ~FILE_STRINGCODE;
565                                 }
566                         }
567                         if(simasel->returnfunc)
568                                 simasel->returnfunc(name);
569                         else if(simasel->returnfunc_args)
570                                 simasel->returnfunc_args(name, simasel->arg1, simasel->arg2);
571                 }
572         }
573 }
574
575 static void do_imasel_buttons(short event, SpaceImaSel *simasel)
576 {
577         char butname[FILE_MAX];
578         
579         if (event == B_FS_FILENAME) {
580                 if (strchr(simasel->file, '*') || strchr(simasel->file, '?') || strchr(simasel->file, '[')) {
581                         int i, match = FALSE;
582                         struct direntry *file;
583                         int n = BIF_filelist_numfiles(simasel->files);
584                         for (i = 2; i < n; i++) {
585                                 file = BIF_filelist_file(simasel->files, i);
586                                 if (fnmatch(simasel->file, file->relname, 0) == 0) {
587                                         file->flags |= ACTIVE;
588                                         match = TRUE;
589                                 }
590                         }
591                         if (match) simasel->file[0] = '\0';
592                         if(simasel->type==FILE_MAIN) imasel_select_objects(simasel);
593                         scrarea_queue_winredraw(curarea);
594                 }
595         }
596         else if(event== B_FS_DIRNAME) {
597                 /* reuse the butname variable */
598                 BLI_cleanup_dir(G.sce, simasel->dir);
599
600                 BLI_make_file_string(G.sce, butname, simasel->dir, "");
601                 BLI_strncpy(simasel->dir, butname, sizeof(simasel->dir));               
602
603                 /* strip the trailing slash if its a real dir */
604                 if (strlen(butname)!=1)
605                         butname[strlen(butname)-1]=0;
606                 
607                 /* updating the directory in the filelist */
608                 BIF_filelist_setdir(simasel->files, simasel->dir);
609
610                 if(simasel->type & FILE_UNIX) {
611                         if (!BLI_exists(butname)) {
612                                 if (okee("Makedir")) {
613                                         BLI_recurdir_fileops(butname);
614                                         if (!BLI_exists(butname)) {
615                                                 BIF_filelist_free(simasel->files);
616                                                 BIF_filelist_parent(simasel->files);
617                                                 BLI_strncpy(simasel->dir, BIF_filelist_dir(simasel->files), 80);
618                                         }
619                                 } else {
620                                         BIF_filelist_free(simasel->files);
621                                         BIF_filelist_parent(simasel->files);
622                                         BLI_strncpy(simasel->dir, BIF_filelist_dir(simasel->files), 80);
623                                 }
624                         }
625                 }
626                 BIF_filelist_free(simasel->files);              
627                 simasel->file[0] = '\0';                        
628                 simasel->scrollpos = 0;
629                 simasel->active_file = -1;
630                 scrarea_queue_winredraw(curarea);
631         }
632         else if(event== B_FS_DIR_MENU) {
633                 char *selected= fsmenu_get_entry(simasel->menu-1);
634                 
635                 /* which string */
636                 if (selected) {
637                         BLI_strncpy(simasel->dir, selected, sizeof(simasel->dir));
638                         BLI_cleanup_dir(G.sce, simasel->dir);
639                         BIF_filelist_free(simasel->files);      
640                         BIF_filelist_setdir(simasel->files, simasel->dir);
641                         simasel->file[0] = '\0';                        
642                         simasel->scrollpos = 0;
643                         simasel->active_file = -1;
644                         scrarea_queue_redraw(curarea);
645                 }
646
647                 simasel->active_file = -1;
648                 
649         }
650         else if(event== B_FS_PARDIR) {
651                 BIF_filelist_free(simasel->files);
652                 BIF_filelist_parent(simasel->files);
653                 BLI_strncpy(simasel->dir, BIF_filelist_dir(simasel->files), 80);
654                 simasel->file[0] = '\0';
655                 simasel->active_file = -1;
656                 simasel->scrollpos = 0;
657                 scrarea_queue_redraw(curarea);
658         }
659         else if(event== B_FS_LOAD) {
660                 if(simasel->type) 
661                         imasel_execute(simasel);
662         }
663         else if(event== B_FS_CANCEL) 
664                 imasel_prevspace();
665         else if(event== B_FS_LIBNAME) {
666                 Library *lib= BLI_findlink(&G.main->library, simasel->menu);
667                 if(lib) {
668                         BLI_strncpy(simasel->dir, lib->filename, sizeof(simasel->dir));
669                         BLI_make_exist(simasel->dir);
670                         BLI_cleanup_dir(G.sce, simasel->dir);
671                         BIF_filelist_free(simasel->files);
672                         BIF_filelist_setdir(simasel->files, simasel->dir);
673                         simasel->file[0] = '\0';                        
674                         simasel->scrollpos = 0;
675                         simasel->active_file = -1;
676                         scrarea_queue_winredraw(curarea);
677                 }
678         } else if(event== B_FS_BOOKMARK)  {
679                 char name[FILE_MAX];
680                 BLI_make_file_string(G.sce, name, BLI_gethome(), ".Bfs");
681                 fsmenu_insert_entry(simasel->dir, 1, 1);
682                 scrarea_queue_winredraw(curarea);
683                 fsmenu_write_file(name);
684         }
685         
686 }
687
688 static void imasel_home(ScrArea *sa, SpaceImaSel *simasel)
689 {
690         simasel->v2d.cur.xmin= simasel->v2d.cur.ymin= 0.0f;
691         simasel->v2d.cur.xmax= sa->winx;
692         simasel->v2d.cur.ymax= sa->winy;
693         
694         simasel->v2d.tot= simasel->v2d.cur;
695         test_view2d(G.v2d, sa->winx, sa->winy);
696         
697 }
698
699 static struct direntry* get_hilited_entry(SpaceImaSel *simasel)
700 {
701         struct direntry *file;
702         file = BIF_filelist_file(simasel->files, simasel->active_file);
703         return file;
704 }
705
706 static void do_filescroll(SpaceImaSel *simasel)
707 {
708         short mval[2], oldy, yo;
709         float scrollarea, scrollstep;
710
711         /* for beauty */
712         scrarea_do_windraw(curarea);
713         screen_swapbuffers();
714
715         getmouseco_areawin(mval);
716         oldy= yo= mval[1];
717         
718         while(get_mbut()&L_MOUSE) {
719                 getmouseco_areawin(mval);
720                 
721                 if(yo!=mval[1]) {
722                         scrollarea = ((float)simasel->v2d.vert.ymax - (float)simasel->v2d.vert.ymin);
723                         scrollstep = yo - mval[1];      
724                         simasel->scrollpos += scrollstep;
725                         
726                         if (simasel->scrollpos<0) 
727                                 simasel->scrollpos=0;
728                         if (simasel->scrollpos > scrollarea - simasel->scrollheight) 
729                                 simasel->scrollpos = scrollarea - simasel->scrollheight;
730                         scrarea_do_windraw(curarea);
731                         screen_swapbuffers();
732
733                         yo= mval[1];
734                 }
735                 else BIF_wait_for_statechange();
736         }
737
738         /* for beauty */
739         scrarea_do_windraw(curarea);
740         screen_swapbuffers();
741         
742 }
743
744 /* ******************* DATA SELECT ********************* */
745
746 static void imasel_select_objects(SpaceImaSel *simasel)
747 {
748         Object *ob;
749         Base *base;
750         Scene *sce;
751         struct direntry* file;
752         int a;
753         int totfile;
754
755         /* only when F4 DATABROWSE */
756         if(imasel_has_func(simasel)) return;
757         
758         totfile = BIF_filelist_numfiles(simasel->files);
759
760         if( strcmp(simasel->dir, "Object/")==0 ) {
761                 for(a=0; a<totfile; a++) {
762                         file = BIF_filelist_file(simasel->files, a);
763                         ob= (Object *)file->poin;
764                         
765                         if(ob) {
766                                 if(file->flags & ACTIVE) ob->flag |= SELECT;
767                                 else ob->flag &= ~SELECT;
768                         }
769
770                 }
771                 base= FIRSTBASE;
772                 while(base) {
773                         base->flag= base->object->flag;
774                         base= base->next;
775                 }
776                 countall();
777                 allqueue(REDRAWVIEW3D, 0);
778                 allqueue(REDRAWOOPS, 0);
779         }
780         else if( strcmp(simasel->dir, "Scene/")==0 ) {
781                 
782                 for(a=0; a<totfile; a++) {
783                         file = BIF_filelist_file(simasel->files, a);
784                         sce= (Scene *)file->poin;
785                         if(sce) {
786                                 if(file->flags & ACTIVE) sce->r.scemode |= R_BG_RENDER;
787                                 else sce->r.scemode &= ~R_BG_RENDER;
788                         }
789
790                 }
791                 allqueue(REDRAWBUTSSCENE, 0);
792         }
793 }
794
795 static void active_imasel_object(SpaceImaSel *simasel)
796 {
797         Object *ob;
798         struct direntry* file;
799
800         /* only when F4 DATABROWSE */
801         if(imasel_has_func(simasel)) return;
802         
803         if( strcmp(simasel->dir, "Object/")==0 ) {
804                 int n = BIF_filelist_numfiles(simasel->files);
805                 if(simasel->active_file >= 0 && simasel->active_file < n) {
806                         file = BIF_filelist_file(simasel->files, simasel->active_file);
807                         ob= (Object *)file->poin;
808                         
809                         if(ob) {
810                                 set_active_object(ob);
811                                 if(BASACT && BASACT->object==ob) {
812                                         BASACT->flag |= SELECT;
813                                         file->flags |= ACTIVE;
814                                         allqueue(REDRAWVIEW3D, 0);
815                                         allqueue(REDRAWOOPS, 0);
816                                         scrarea_queue_winredraw(curarea);
817                                 }
818                         }
819                 }
820         }
821 }
822
823
824
825 void winqreadimaselspace(ScrArea *, void *, BWinEvent *);
826
827
828 void winqreadimaselspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
829 {
830         unsigned short event= evt->event;
831         short val= evt->val;
832         SpaceImaSel *simasel;
833         
834         char str[FILE_MAXDIR+FILE_MAXFILE+12];
835         short mval[2];
836         short do_draw = 0;
837         short do_headdraw = 0;
838         int numfiles;
839         struct direntry *file;
840         float scrollstep = 0;
841         float scrollarea;
842
843         // if(val==0) return;
844         simasel= curarea->spacedata.first;
845
846         if (!simasel->files)
847                 return;
848
849         if (BIF_filelist_empty(simasel->files))
850                 return;
851
852         numfiles = BIF_filelist_numfiles(simasel->files);
853         
854         /* calc_scrollrcts(sa, &(simasel->v2d), sa->winx, sa->winy); */
855         calc_imasel_rcts(simasel, sa->winx, sa->winy);  
856
857         /* prevent looping */
858         if(simasel->selstate && !(get_mbut() & R_MOUSE)) simasel->selstate= 0;
859
860         if(val) {
861
862                 if( event!=RETKEY && event!=PADENTER)
863                         if( uiDoBlocks(&curarea->uiblocks, event, 1)!=UI_NOTHING ) event= 0;
864
865                 switch(event) {
866                 
867                 case UI_BUT_EVENT:
868                         do_imasel_buttons(val, simasel);
869                         break;          
870                 case RENDERPREVIEW:
871                         do_draw= 1; 
872                         /* draw_imasel_previews(sa, simasel);  */
873                         break;
874                 case REDRAWIMASEL:
875                         do_draw= 1;
876                         break;
877                 case WHEELDOWNMOUSE:
878                         numfiles = BIF_filelist_numfiles(simasel->files);
879                         scrollarea = ((float)simasel->v2d.vert.ymax - (float)simasel->v2d.vert.ymin);
880                         scrollstep = ((scrollarea-simasel->scrollheight)/numfiles)*simasel->numtilesx;  
881                         simasel->scrollpos += scrollstep;
882                         if (simasel->scrollpos > scrollarea - simasel->scrollheight) 
883                                 simasel->scrollpos = scrollarea - simasel->scrollheight;
884                         do_draw= 1;
885                         break;
886                 case WHEELUPMOUSE:
887                         numfiles = BIF_filelist_numfiles(simasel->files);
888                         scrollarea = ((float)simasel->v2d.vert.ymax - (float)simasel->v2d.vert.ymin);
889                         scrollstep = ((scrollarea-simasel->scrollheight)/numfiles)*simasel->numtilesx;                  
890                         simasel->scrollpos -= scrollstep;
891                         if (simasel->scrollpos<0) 
892                                 simasel->scrollpos=0;
893                         do_draw= 1;
894                         break;
895                 case PAGEUPKEY:
896                         numfiles = BIF_filelist_numfiles(simasel->files);
897                         scrollarea = ((float)simasel->v2d.vert.ymax - (float)simasel->v2d.vert.ymin);
898                         scrollstep = ((scrollarea-simasel->scrollheight)/numfiles)
899                                                  *simasel->numtilesx*simasel->numtilesy;
900                         simasel->scrollpos -= scrollstep;
901                         if (simasel->scrollpos<0) 
902                                 simasel->scrollpos=0;
903                         do_draw= 1;
904                         break;
905                 case PAGEDOWNKEY:
906                         numfiles = BIF_filelist_numfiles(simasel->files);
907                         scrollarea = ((float)simasel->v2d.vert.ymax - (float)simasel->v2d.vert.ymin);
908                         scrollstep = ((scrollarea-simasel->scrollheight)/numfiles)
909                                                  * simasel->numtilesx*simasel->numtilesy;
910                         simasel->scrollpos += scrollstep;
911                         if (simasel->scrollpos > scrollarea - simasel->scrollheight) 
912                                 simasel->scrollpos = scrollarea - simasel->scrollheight;
913                         do_draw= 1;                                             
914                         break;
915                 case HOMEKEY:
916                         simasel->scrollpos=0;
917                         imasel_home(sa, simasel);
918                         do_draw= 1;
919                         break;
920                 case ENDKEY:
921                         simasel->scrollpos = simasel->scrollarea;
922                         do_draw= 1;
923                         break;
924
925                 case ESCKEY:
926                         BIF_filelist_free(simasel->files);
927                         imasel_prevspace();
928                         break;
929                 case PERIODKEY:
930                         BIF_filelist_free(simasel->files);
931                         simasel->active_file = -1;
932                         do_draw = 1;
933                         break;
934                 case LEFTMOUSE:
935                 case MIDDLEMOUSE:                       
936                         getmouseco_areawin(mval);
937                         if(mval[0]>simasel->v2d.vert.xmin && mval[0]<simasel->v2d.vert.xmax && mval[1]>simasel->v2d.vert.ymin && mval[1]<simasel->v2d.vert.ymax) {
938                                 do_filescroll(simasel);
939                         }
940                         else if(mval[0]>simasel->viewrect.xmin && mval[0]<simasel->viewrect.xmax 
941                                 && mval[1]>simasel->viewrect.ymin && mval[1]<simasel->viewrect.ymax) {  
942                                 set_active_file(simasel, mval[0], mval[1]);
943                                 if (simasel->active_file >= 0 && simasel->active_file < numfiles) {
944                                         file = BIF_filelist_file(simasel->files, simasel->active_file);
945                                         
946                                         if(file && S_ISDIR(file->type)) {
947                                                 strcat(simasel->dir, file->relname);                                            
948                                                 strcat(simasel->dir,"/");
949                                                 simasel->file[0] = '\0';
950                                                 BLI_cleanup_dir(G.sce, simasel->dir);
951                                                 BIF_filelist_setdir(simasel->files, simasel->dir);
952                                                 BIF_filelist_free(simasel->files);
953                                                 simasel->active_file = -1;
954                                                 simasel->scrollpos = 0;
955                                                 do_draw = 1;
956                                                 do_headdraw = 1;                                                
957                                         }
958                                         else if (file)
959                                         {
960                                                 if (file->relname) {
961                                                         if (simasel->img) {
962                                                                 IMB_freeImBuf(simasel->img);
963                                                                 simasel->img = NULL;
964                                                         }
965                                                         BLI_strncpy(simasel->file, file->relname, FILE_MAXFILE);
966                                                         if(event==MIDDLEMOUSE && BIF_filelist_gettype(simasel->files)) 
967                                                                 imasel_execute(simasel);
968                                                 }
969                                                 
970                                         }       
971                                         if(BIF_filelist_gettype(simasel->files)==FILE_MAIN) {
972                                                 active_imasel_object(simasel);
973                                         }
974                                 
975                                         do_draw = 1;
976                                 }
977                         }
978                         else {
979                                 simasel->active_file = -1;
980                                 if (simasel->flag & FILE_BOOKMARKS) {
981                                         if(mval[0]>simasel->bookmarkrect.xmin && mval[0]<simasel->bookmarkrect.xmax && mval[1]>simasel->bookmarkrect.ymin && mval[1]<simasel->bookmarkrect.ymax) {
982                                                 int nentries = fsmenu_get_nentries();
983                                                 
984                                                 set_active_bookmark(simasel, mval[1]);
985                                                 if (simasel->active_bookmark >= 0 && simasel->active_bookmark < nentries) {
986                                                         char *selected= fsmenu_get_entry(simasel->active_bookmark);                     
987                                                         /* which string */
988                                                         if (selected) {
989                                                                 BLI_strncpy(simasel->dir, selected, sizeof(simasel->dir));
990                                                                 BLI_cleanup_dir(G.sce, simasel->dir);
991                                                                 BIF_filelist_free(simasel->files);      
992                                                                 BIF_filelist_setdir(simasel->files, simasel->dir);
993                                                                 simasel->file[0] = '\0';                        
994                                                                 simasel->scrollpos = 0;
995                                                                 simasel->active_file = -1;
996                                                                 do_headdraw = 1;
997                                                         }
998                                                 }
999                                         } else {
1000                                                 simasel->active_bookmark = -1;
1001                                         }
1002                                         do_draw= 1;
1003                                 }                               
1004                         }
1005                         break;
1006                 case RIGHTMOUSE:                        
1007                         getmouseco_areawin(mval);
1008                         if(mval[0]>simasel->viewrect.xmin && mval[0]<simasel->viewrect.xmax 
1009                                 && mval[1]>simasel->viewrect.ymin && mval[1]<simasel->viewrect.ymax) {
1010                                 set_active_file(simasel, mval[0], mval[1]);
1011                                 if(simasel->active_file >=0 && simasel->active_file<numfiles) {
1012                                         simasel->selstate = NOTACTIVE;
1013                                         file = BIF_filelist_file(simasel->files, simasel->active_file);
1014                                         if (file->flags & ACTIVE) {
1015                                                 file->flags &= ~ACTIVE;
1016                                                 simasel->selstate = INACTIVATE;
1017                                         }
1018                                         else {
1019                                                 file->flags |= ACTIVE;
1020                                                 simasel->selstate = ACTIVATE;
1021                                         }
1022                                         do_draw= 1;
1023                                 }
1024                         }
1025                         break;
1026                 case MOUSEY:
1027                 case MOUSEX:
1028                         getmouseco_areawin(mval);
1029                         if(mval[0]>simasel->viewrect.xmin && mval[0]<simasel->viewrect.xmax && mval[1]>simasel->viewrect.ymin && mval[1]<simasel->viewrect.ymax) {
1030                                 set_active_file(simasel, mval[0], mval[1]);
1031                                 simasel->active_bookmark = -1;
1032                                 if(simasel->active_file >=0 && simasel->active_file<numfiles) {
1033                                         file = BIF_filelist_file(simasel->files, simasel->active_file);
1034                                         if (simasel->selstate == INACTIVATE) {
1035                                                 file->flags &= ~ACTIVE;
1036                                         }
1037                                         else if (simasel->selstate == ACTIVATE) {
1038                                                 file->flags |= ACTIVE;
1039                                         }
1040                                         do_draw= 1;
1041                                 }
1042                         } else {
1043                                 simasel->active_file = -1;                      
1044                                 if (simasel->flag & FILE_BOOKMARKS) {
1045                                         if(mval[0]>simasel->bookmarkrect.xmin && mval[0]<simasel->bookmarkrect.xmax && mval[1]>simasel->bookmarkrect.ymin && mval[1]<simasel->bookmarkrect.ymax) {
1046                                                 set_active_bookmark(simasel, mval[1]);                                          
1047                                         } else {
1048                                                 simasel->active_bookmark = -1;
1049                                         }
1050                                         do_draw= 1;
1051                                 }
1052                         }
1053                         break;
1054                 case AKEY:
1055                         BIF_filelist_swapselect(simasel->files);
1056                         if(simasel->type==FILE_MAIN) imasel_select_objects(simasel);
1057                         do_draw= 1;
1058                         break;
1059                 case BKEY:
1060                         toggle_blockhandler(sa, IMASEL_HANDLER_IMAGE, UI_PNL_UNSTOW);
1061                         scrarea_queue_winredraw(sa);
1062                         break;
1063                 case PKEY:
1064                         if(G.qual & LR_SHIFTKEY) {
1065                                 extern char bprogname[];        /* usiblender.c */
1066                         
1067                                 sprintf(str, "%s -a \"%s%s\"", bprogname, simasel->dir, simasel->file);
1068                                 system(str);
1069                         }
1070                         else 
1071                         {
1072                                 BIF_filelist_free(simasel->files);
1073                                 BIF_filelist_parent(simasel->files);
1074                                 BLI_strncpy(simasel->dir, BIF_filelist_dir(simasel->files), 80);
1075                                 simasel->file[0] = '\0';
1076                                 simasel->active_file = -1;
1077                                 simasel->scrollpos = 0;
1078                                 do_headdraw = 1;
1079                         }
1080                         do_draw = 1;    
1081                         break;
1082                 case XKEY:
1083                         getmouseco_areawin(mval);                       
1084                         if (simasel->flag & FILE_BOOKMARKS) {
1085                                 if(mval[0]>simasel->bookmarkrect.xmin && mval[0]<simasel->bookmarkrect.xmax && mval[1]>simasel->bookmarkrect.ymin && mval[1]<simasel->bookmarkrect.ymax) {                      
1086                                         int nentries = fsmenu_get_nentries();
1087                                         set_active_bookmark(simasel, mval[1]);
1088                                         if (simasel->active_bookmark >= 0 && simasel->active_bookmark < nentries) {
1089                                                 char name[FILE_MAX];
1090                                                 BLI_make_file_string(G.sce, name, BLI_gethome(), ".Bfs");
1091                                                 fsmenu_remove_entry(simasel->active_bookmark);
1092                                                 fsmenu_write_file(name);
1093                                                 simasel->active_bookmark = -1;
1094                                                 do_draw = 1;
1095                                         }
1096                                 }
1097                         }                       
1098                         break;
1099                 }               
1100         }
1101         else if(event==RIGHTMOUSE) {
1102                 simasel->selstate = NOTACTIVE;          
1103                 if(simasel->type==FILE_MAIN) imasel_select_objects(simasel);
1104         }
1105         else if(event==LEFTMOUSE) {
1106                 if(simasel->type==FILE_MAIN) {
1107                         getmouseco_areawin(mval);
1108                         set_active_file(simasel, mval[0], mval[1]);
1109                 }
1110         }
1111                 /* XXX, stupid patch, curarea can become undone
1112                  * because of file loading... fixme zr
1113                  */
1114         if(curarea) {
1115                 if(do_draw) scrarea_queue_winredraw(curarea);
1116                 if(do_headdraw) scrarea_queue_headredraw(curarea);
1117         }
1118 }
1119
1120
1121 /* copied from filesel.c */
1122 void clever_numbuts_imasel()
1123 {
1124         SpaceImaSel *simasel;
1125         char orgname[FILE_MAXDIR+FILE_MAXFILE+12];
1126         char filename[FILE_MAXDIR+FILE_MAXFILE+12];
1127         char newname[FILE_MAXDIR+FILE_MAXFILE+12];
1128         struct direntry *file;
1129         int len;
1130         
1131         simasel= curarea->spacedata.first;
1132
1133         if(BIF_filelist_gettype(simasel->files)==FILE_MAIN) return;
1134         
1135         len = 110;
1136         file = get_hilited_entry(simasel);
1137
1138         if (file != NULL && !(S_ISDIR(file->type))){
1139                 
1140                 BLI_make_file_string(G.sce, orgname, simasel->dir, file->relname);
1141                 BLI_strncpy(filename, file->relname, sizeof(filename));
1142
1143                 add_numbut(0, TEX, "", 0, len, filename, "Rename File");
1144
1145                 if( do_clever_numbuts("Rename File", 1, REDRAW) ) {
1146                         BLI_make_file_string(G.sce, newname, simasel->dir, filename);
1147
1148                         if( strcmp(orgname, newname) != 0 ) {
1149                                 BLI_rename(orgname, newname);
1150                                 BIF_filelist_free(simasel->files);
1151                         }
1152                 }
1153
1154                 scrarea_queue_winredraw(curarea);
1155         }
1156 }