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