Merge of itasc branch. Project files, scons and cmake should be working. Makefile...
[blender.git] / source / blender / editors / space_file / file_ops.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL 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. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Andrea Weikert (c) 2008 Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include "BKE_context.h"
30 #include "BKE_screen.h"
31 #include "BKE_global.h"
32
33 #include "BLI_blenlib.h"
34 #include "BLI_storage_types.h"
35 #ifdef WIN32
36 #include "BLI_winstuff.h"
37 #endif
38 #include "DNA_space_types.h"
39 #include "DNA_userdef_types.h"
40
41 #include "ED_space_api.h"
42 #include "ED_screen.h"
43 #include "ED_fileselect.h"
44
45 #include "MEM_guardedalloc.h"
46
47 #include "RNA_access.h"
48 #include "RNA_define.h"
49
50 #include "UI_interface.h"
51 #include "UI_view2d.h"
52
53 #include "WM_api.h"
54 #include "WM_types.h"
55
56 #include "file_intern.h"
57 #include "filelist.h"
58 #include "fsmenu.h"
59
60 #include <stdlib.h>
61 #include <string.h>
62 #include <stdio.h>
63
64 /* for events */
65 #define NOTACTIVE                       0
66 #define ACTIVATE                        1
67 #define INACTIVATE                      2
68
69 /* ---------- FILE SELECTION ------------ */
70
71 static int find_file_mouse(SpaceFile *sfile, struct ARegion* ar, short x, short y)
72 {
73         float fx,fy;
74         int active_file = -1;
75         View2D* v2d = &ar->v2d;
76
77         UI_view2d_region_to_view(v2d, x, y, &fx, &fy);
78
79         active_file = ED_fileselect_layout_offset(sfile->layout, v2d->tot.xmin + fx, v2d->tot.ymax - fy);
80         
81         return active_file;
82 }
83
84
85 static void file_deselect_all(SpaceFile* sfile)
86 {
87         int numfiles = filelist_numfiles(sfile->files);
88         int i;
89
90         for ( i=0; i < numfiles; ++i) {
91                 struct direntry* file = filelist_file(sfile->files, i);
92                 if (file && (file->flags & ACTIVE)) {
93                         file->flags &= ~ACTIVE;
94                 }
95         }
96 }
97
98 typedef enum FileSelect { FILE_SELECT_DIR = 1, 
99   FILE_SELECT_FILE = 2 } FileSelect;
100
101
102 static void clamp_to_filelist(int numfiles, int *first_file, int *last_file)
103 {
104         /* border select before the first file */
105         if ( (*first_file < 0) && (*last_file >=0 ) ) {
106                 *first_file = 0;
107         }
108         /* don't select if everything is outside filelist */
109         if ( (*first_file >= numfiles) && ((*last_file < 0) || (*last_file >= numfiles)) ) {
110                 *first_file = -1;
111                 *last_file = -1;
112         }
113         
114         /* fix if last file invalid */
115         if ( (*first_file > 0) && (*last_file < 0) )
116                 *last_file = numfiles-1;
117
118         /* clamp */
119         if ( (*first_file >= numfiles) ) {
120                 *first_file = numfiles-1;
121         }
122         if ( (*last_file >= numfiles) ) {
123                 *last_file = numfiles-1;
124         }
125 }
126
127 static FileSelect file_select(SpaceFile* sfile, ARegion* ar, const rcti* rect, short val)
128 {
129         int first_file = -1;
130         int last_file = -1;
131         int act_file;
132         short selecting = (val == LEFTMOUSE);
133         FileSelect retval = FILE_SELECT_FILE;
134
135         FileSelectParams *params = ED_fileselect_get_params(sfile);
136         // FileLayout *layout = ED_fileselect_get_layout(sfile, ar);
137
138         int numfiles = filelist_numfiles(sfile->files);
139
140         params->selstate = NOTACTIVE;
141         first_file = find_file_mouse(sfile, ar, rect->xmin, rect->ymax);
142         last_file = find_file_mouse(sfile, ar, rect->xmax, rect->ymin);
143         
144         clamp_to_filelist(numfiles, &first_file, &last_file);
145
146         /* select all valid files between first and last indicated */
147         if ( (first_file >= 0) && (first_file < numfiles) && (last_file >= 0) && (last_file < numfiles) ) {
148                 for (act_file = first_file; act_file <= last_file; act_file++) {
149                         struct direntry* file = filelist_file(sfile->files, act_file);
150                         if (selecting) 
151                                 file->flags |= ACTIVE;
152                         else
153                                 file->flags &= ~ACTIVE;
154                 }
155         }
156
157         /* Don't act on multiple selected files */
158         if (first_file != last_file) selecting= 0;
159
160         /* make the last file active */
161         if (selecting && (last_file >= 0 && last_file < numfiles)) {
162                 struct direntry* file = filelist_file(sfile->files, last_file);
163                 params->active_file = last_file;
164
165                 if(file && S_ISDIR(file->type)) {
166                         /* the path is too long and we are not going up! */
167                         if (strcmp(file->relname, "..") && strlen(params->dir) + strlen(file->relname) >= FILE_MAX ) 
168                         {
169                                 // XXX error("Path too long, cannot enter this directory");
170                         } else {
171                                 if (strcmp(file->relname, "..")==0) {    
172                                         /* avoids /../../ */     
173                                         BLI_parent_dir(params->dir);     
174                                 } else {
175                                         BLI_cleanup_dir(G.sce, params->dir);
176                                         strcat(params->dir, file->relname);
177                                         BLI_add_slash(params->dir);
178                                 }
179
180                                 file_change_dir(sfile);
181                                 retval = FILE_SELECT_DIR;
182                         }
183                 }
184                 else if (file)
185                 {
186                         if (file->relname) {
187                                 BLI_strncpy(params->file, file->relname, FILE_MAXFILE);
188                         }
189                         
190                 }       
191         } 
192         return retval;
193 }
194
195
196
197 static int file_border_select_exec(bContext *C, wmOperator *op)
198 {
199         ARegion *ar= CTX_wm_region(C);
200         SpaceFile *sfile= CTX_wm_space_file(C);
201         short val;
202         rcti rect;
203
204         val= RNA_int_get(op->ptr, "event_type");
205         rect.xmin= RNA_int_get(op->ptr, "xmin");
206         rect.ymin= RNA_int_get(op->ptr, "ymin");
207         rect.xmax= RNA_int_get(op->ptr, "xmax");
208         rect.ymax= RNA_int_get(op->ptr, "ymax");
209
210         BLI_isect_rcti(&(ar->v2d.mask), &rect, &rect);
211         
212         if (FILE_SELECT_DIR == file_select(sfile, ar, &rect, val )) {
213                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
214         } else {
215                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_PARAMS, NULL);
216         }
217         return OPERATOR_FINISHED;
218 }
219
220 void FILE_OT_select_border(wmOperatorType *ot)
221 {
222         /* identifiers */
223         ot->name= "Activate/Select File";
224         ot->idname= "FILE_OT_select_border";
225         
226         /* api callbacks */
227         ot->invoke= WM_border_select_invoke;
228         ot->exec= file_border_select_exec;
229         ot->modal= WM_border_select_modal;
230
231         /* rna */
232         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
233         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
234         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
235         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
236         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
237
238         ot->poll= ED_operator_file_active;
239 }
240
241 static int file_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
242 {
243         ARegion *ar= CTX_wm_region(C);
244         SpaceFile *sfile= CTX_wm_space_file(C);
245         short val;
246         rcti rect;
247
248         if(ar->regiontype != RGN_TYPE_WINDOW)
249                 return OPERATOR_CANCELLED;
250
251         rect.xmin = rect.xmax = event->x - ar->winrct.xmin;
252         rect.ymin = rect.ymax = event->y - ar->winrct.ymin;
253         val = event->val;
254
255         if(!BLI_in_rcti(&ar->v2d.mask, rect.xmin, rect.ymin))
256                 return OPERATOR_CANCELLED;
257
258         /* single select, deselect all selected first */
259         file_deselect_all(sfile);
260
261         if (FILE_SELECT_DIR == file_select(sfile, ar, &rect, val ))
262                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
263         else
264                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_PARAMS, NULL);
265
266         WM_event_add_mousemove(C); /* for directory changes */
267         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_PARAMS, NULL);
268
269         return OPERATOR_FINISHED;
270 }
271
272 void FILE_OT_select(wmOperatorType *ot)
273 {
274         /* identifiers */
275         ot->name= "Activate/Select File";
276         ot->idname= "FILE_OT_select";
277         
278         /* api callbacks */
279         ot->invoke= file_select_invoke;
280
281         /* rna */
282
283         ot->poll= ED_operator_file_active;
284 }
285
286 static int file_select_all_invoke(bContext *C, wmOperator *op, wmEvent *event)
287 {
288         ScrArea *sa= CTX_wm_area(C);
289         SpaceFile *sfile= CTX_wm_space_file(C);
290         int numfiles = filelist_numfiles(sfile->files);
291         int i;
292         int select = 1;
293
294         /* if any file is selected, deselect all first */
295         for ( i=0; i < numfiles; ++i) {
296                 struct direntry* file = filelist_file(sfile->files, i);
297                 if (file && (file->flags & ACTIVE)) {
298                         file->flags &= ~ACTIVE;
299                         select = 0;
300                         ED_area_tag_redraw(sa);
301                 }
302         }
303         /* select all only if previously no file was selected */
304         if (select) {
305                 for ( i=0; i < numfiles; ++i) {
306                         struct direntry* file = filelist_file(sfile->files, i);
307                         if(file && !S_ISDIR(file->type)) {
308                                 file->flags |= ACTIVE;
309                                 ED_area_tag_redraw(sa);
310                         }
311                 }
312         }
313         return OPERATOR_FINISHED;
314 }
315
316 void FILE_OT_select_all_toggle(wmOperatorType *ot)
317 {
318         /* identifiers */
319         ot->name= "Select/Deselect all files";
320         ot->idname= "FILE_OT_select_all_toggle";
321         
322         /* api callbacks */
323         ot->invoke= file_select_all_invoke;
324
325         /* rna */
326
327         ot->poll= ED_operator_file_active;
328 }
329
330 /* ---------- BOOKMARKS ----------- */
331
332 static int bookmark_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
333 {
334         SpaceFile *sfile= CTX_wm_space_file(C);
335
336         if(RNA_struct_find_property(op->ptr, "dir")) {
337                 char entry[256];
338                 FileSelectParams* params = sfile->params;
339
340                 RNA_string_get(op->ptr, "dir", entry);
341                 BLI_strncpy(params->dir, entry, sizeof(params->dir));
342                 BLI_cleanup_dir(G.sce, params->dir);
343                 file_change_dir(sfile);                         
344
345                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
346         }
347         
348         return OPERATOR_FINISHED;
349 }
350
351 void FILE_OT_select_bookmark(wmOperatorType *ot)
352 {
353         /* identifiers */
354         ot->name= "Select Directory";
355         ot->idname= "FILE_OT_select_bookmark";
356         
357         /* api callbacks */
358         ot->invoke= bookmark_select_invoke;
359         ot->poll= ED_operator_file_active;
360
361         RNA_def_string(ot->srna, "dir", "", 256, "Dir", "");
362 }
363
364 static int bookmark_add_invoke(bContext *C, wmOperator *op, wmEvent *event)
365 {
366         ScrArea *sa= CTX_wm_area(C);
367         SpaceFile *sfile= CTX_wm_space_file(C);
368         struct FSMenu* fsmenu = fsmenu_get();
369         struct FileSelectParams* params= ED_fileselect_get_params(sfile);
370
371         if (params->dir[0] != '\0') {
372                 char name[FILE_MAX];
373         
374                 fsmenu_insert_entry(fsmenu, FS_CATEGORY_BOOKMARKS, params->dir, 0, 1);
375                 BLI_make_file_string("/", name, BLI_gethome(), ".Bfs");
376                 fsmenu_write_file(fsmenu, name);
377         }
378
379         ED_area_tag_redraw(sa);
380         return OPERATOR_FINISHED;
381 }
382
383 void FILE_OT_add_bookmark(wmOperatorType *ot)
384 {
385         /* identifiers */
386         ot->name= "Add Bookmark";
387         ot->idname= "FILE_OT_add_bookmark";
388         
389         /* api callbacks */
390         ot->invoke= bookmark_add_invoke;
391         ot->poll= ED_operator_file_active;
392 }
393
394 static int bookmark_delete_invoke(bContext *C, wmOperator *op, wmEvent *event)
395 {
396         ScrArea *sa= CTX_wm_area(C);
397         struct FSMenu* fsmenu = fsmenu_get();
398         int nentries = fsmenu_get_nentries(fsmenu, FS_CATEGORY_BOOKMARKS);
399         
400         if(RNA_struct_find_property(op->ptr, "index")) {
401                 int index = RNA_int_get(op->ptr, "index");
402                 if ( (index >-1) && (index < nentries)) {
403                         char name[FILE_MAX];
404                         
405                         fsmenu_remove_entry(fsmenu, FS_CATEGORY_BOOKMARKS, index);
406                         BLI_make_file_string("/", name, BLI_gethome(), ".Bfs");
407                         fsmenu_write_file(fsmenu, name);
408                         ED_area_tag_redraw(sa);
409                 }
410         }
411
412         return OPERATOR_FINISHED;
413 }
414
415 void FILE_OT_delete_bookmark(wmOperatorType *ot)
416 {
417         /* identifiers */
418         ot->name= "Delete Bookmark";
419         ot->idname= "FILE_OT_delete_bookmark";
420         
421         /* api callbacks */
422         ot->invoke= bookmark_delete_invoke;
423         ot->poll= ED_operator_file_active;
424
425         RNA_def_int(ot->srna, "index", -1, -1, 20000, "Index", "", -1, 20000);
426 }
427
428
429 static int loadimages_invoke(bContext *C, wmOperator *op, wmEvent *event)
430 {
431         ScrArea *sa= CTX_wm_area(C);
432         SpaceFile *sfile= CTX_wm_space_file(C);
433         if (sfile->files) {
434                 filelist_loadimage_timer(sfile->files);
435                 if (filelist_changed(sfile->files)) {
436                         ED_area_tag_redraw(sa);
437                 }
438         }
439
440         return OPERATOR_FINISHED;
441 }
442
443 void FILE_OT_loadimages(wmOperatorType *ot)
444 {
445         
446         /* identifiers */
447         ot->name= "Load Images";
448         ot->idname= "FILE_OT_loadimages";
449         
450         /* api callbacks */
451         ot->invoke= loadimages_invoke;
452         
453         ot->poll= ED_operator_file_active;
454 }
455
456 int file_hilight_set(SpaceFile *sfile, ARegion *ar, int mx, int my)
457 {
458         FileSelectParams* params;
459         int numfiles, actfile, origfile;
460         
461         if(sfile==NULL || sfile->files==NULL) return 0;
462
463         numfiles = filelist_numfiles(sfile->files);
464         params = ED_fileselect_get_params(sfile);
465
466         origfile= params->active_file;
467
468         mx -= ar->winrct.xmin;
469         my -= ar->winrct.ymin;
470
471         if(BLI_in_rcti(&ar->v2d.mask, mx, my)) {
472                 actfile = find_file_mouse(sfile, ar, mx , my);
473
474                 if((actfile >= 0) && (actfile < numfiles))
475                         params->active_file=actfile;
476                 else
477                         params->active_file= -1;
478         }
479         else
480                 params->active_file= -1;
481
482         return (params->active_file != origfile);
483 }
484
485 static int file_highlight_invoke(bContext *C, wmOperator *op, wmEvent *event)
486 {
487         ARegion *ar= CTX_wm_region(C);
488         SpaceFile *sfile= CTX_wm_space_file(C);
489
490         if(!file_hilight_set(sfile, ar, event->x, event->y))
491                 return OPERATOR_CANCELLED;
492
493         ED_area_tag_redraw(CTX_wm_area(C));
494         
495         return OPERATOR_FINISHED;
496 }
497
498 void FILE_OT_highlight(struct wmOperatorType *ot)
499 {
500         /* identifiers */
501         ot->name= "Highlight File";
502         ot->idname= "FILE_OT_highlight";
503         
504         /* api callbacks */
505         ot->invoke= file_highlight_invoke;
506         ot->poll= ED_operator_file_active;
507 }
508
509 int file_cancel_exec(bContext *C, wmOperator *unused)
510 {
511         SpaceFile *sfile= CTX_wm_space_file(C);
512
513         folderlist_free(sfile->folders_prev);
514         folderlist_free(sfile->folders_next);
515
516         WM_event_fileselect_event(C, sfile->op, EVT_FILESELECT_CANCEL);
517         sfile->op = NULL;
518         
519         if (sfile->files) {
520                 filelist_freelib(sfile->files);
521                 filelist_free(sfile->files);
522                 MEM_freeN(sfile->files);
523                 sfile->files= NULL;
524         }
525         
526         return OPERATOR_FINISHED;
527 }
528
529 int file_operator_poll(bContext *C)
530 {
531         int poll = ED_operator_file_active(C);
532         SpaceFile *sfile= CTX_wm_space_file(C);
533
534         if (!sfile || !sfile->op) poll= 0;
535
536         return poll;
537 }
538
539 void FILE_OT_cancel(struct wmOperatorType *ot)
540 {
541         /* identifiers */
542         ot->name= "Cancel File Load";
543         ot->idname= "FILE_OT_cancel";
544         
545         /* api callbacks */
546         ot->exec= file_cancel_exec;
547         ot->poll= file_operator_poll;
548 }
549
550 /* sends events now, so things get handled on windowqueue level */
551 int file_exec(bContext *C, wmOperator *unused)
552 {
553         SpaceFile *sfile= CTX_wm_space_file(C);
554         char name[FILE_MAX];
555         
556         if(sfile->op) {
557                 wmOperator *op= sfile->op;
558                 
559                 sfile->op = NULL;
560                 RNA_string_set(op->ptr, "filename", sfile->params->file);
561                 BLI_strncpy(name, sfile->params->dir, sizeof(name));
562                 RNA_string_set(op->ptr, "directory", name);
563                 strcat(name, sfile->params->file);
564
565                 if(RNA_struct_find_property(op->ptr, "relative_paths"))
566                         if(RNA_boolean_get(op->ptr, "relative_paths"))
567                                 BLI_makestringcode(G.sce, name);
568
569                 RNA_string_set(op->ptr, "path", name);
570                 
571                 /* some ops have multiple files to select */
572                 {
573                         PointerRNA itemptr;
574                         int i, numfiles = filelist_numfiles(sfile->files);
575                         struct direntry *file;
576                         if(RNA_struct_find_property(op->ptr, "files")) {
577                                 for (i=0; i<numfiles; i++) {
578                                         file = filelist_file(sfile->files, i);
579                                         if(file->flags & ACTIVE) {
580                                                 if ((file->type & S_IFDIR)==0) {
581                                                         RNA_collection_add(op->ptr, "files", &itemptr);
582                                                         RNA_string_set(&itemptr, "name", file->relname);
583                                                 }
584                                         }
585                                 }
586                         }
587                         
588                         if(RNA_struct_find_property(op->ptr, "dirs")) {
589                                 for (i=0; i<numfiles; i++) {
590                                         file = filelist_file(sfile->files, i);
591                                         if(file->flags & ACTIVE) {
592                                                 if ((file->type & S_IFDIR)) {
593                                                         RNA_collection_add(op->ptr, "dirs", &itemptr);
594                                                         RNA_string_set(&itemptr, "name", file->relname);
595                                                 }
596                                         }
597                                 }
598                         }
599                 }
600                 
601                 folderlist_free(sfile->folders_prev);
602                 folderlist_free(sfile->folders_next);
603
604                 fsmenu_insert_entry(fsmenu_get(), FS_CATEGORY_RECENT, sfile->params->dir,0, 1);
605                 BLI_make_file_string(G.sce, name, BLI_gethome(), ".Bfs");
606                 fsmenu_write_file(fsmenu_get(), name);
607                 WM_event_fileselect_event(C, op, EVT_FILESELECT_EXEC);
608
609                 filelist_freelib(sfile->files);
610                 filelist_free(sfile->files);
611                 MEM_freeN(sfile->files);
612                 sfile->files= NULL;
613         }
614                                 
615         return OPERATOR_FINISHED;
616 }
617
618 void FILE_OT_execute(struct wmOperatorType *ot)
619 {
620         /* identifiers */
621         ot->name= "Execute File Window";
622         ot->idname= "FILE_OT_execute";
623         
624         /* api callbacks */
625         ot->exec= file_exec;
626         ot->poll= file_operator_poll; 
627 }
628
629
630 int file_parent_exec(bContext *C, wmOperator *unused)
631 {
632         SpaceFile *sfile= CTX_wm_space_file(C);
633         
634         if(sfile->params) {
635                 if (BLI_has_parent(sfile->params->dir)) {
636                         BLI_parent_dir(sfile->params->dir);
637                         BLI_cleanup_dir(G.sce, sfile->params->dir);
638                         file_change_dir(sfile);
639                         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
640                 }
641         }               
642         
643         return OPERATOR_FINISHED;
644
645 }
646
647
648 void FILE_OT_parent(struct wmOperatorType *ot)
649 {
650         /* identifiers */
651         ot->name= "Parent File";
652         ot->idname= "FILE_OT_parent";
653         
654         /* api callbacks */
655         ot->exec= file_parent_exec;
656         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
657 }
658
659
660 int file_refresh_exec(bContext *C, wmOperator *unused)
661 {
662         SpaceFile *sfile= CTX_wm_space_file(C);
663         
664         file_change_dir(sfile);
665
666         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
667
668         return OPERATOR_FINISHED;
669
670 }
671
672 void FILE_OT_previous(struct wmOperatorType *ot)
673 {
674         /* identifiers */
675         ot->name= "Previous Folder";
676         ot->idname= "FILE_OT_previous";
677         
678         /* api callbacks */
679         ot->exec= file_previous_exec;
680         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
681 }
682
683 int file_previous_exec(bContext *C, wmOperator *unused)
684 {
685         SpaceFile *sfile= CTX_wm_space_file(C);
686
687         if(sfile->params) {
688                 if (!sfile->folders_next)
689                         sfile->folders_next = folderlist_new();
690
691                 folderlist_pushdir(sfile->folders_next, sfile->params->dir);
692                 folderlist_popdir(sfile->folders_prev, sfile->params->dir);
693                 folderlist_pushdir(sfile->folders_next, sfile->params->dir);
694
695                 file_change_dir(sfile);
696         }
697         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
698
699         return OPERATOR_FINISHED;
700 }
701
702 void FILE_OT_next(struct wmOperatorType *ot)
703 {
704         /* identifiers */
705         ot->name= "Next Folder";
706         ot->idname= "FILE_OT_next";
707         
708         /* api callbacks */
709         ot->exec= file_next_exec;
710         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
711 }
712
713 int file_next_exec(bContext *C, wmOperator *unused)
714 {
715         SpaceFile *sfile= CTX_wm_space_file(C);
716                 if(sfile->params) {
717                         if (!sfile->folders_next)
718                         sfile->folders_next = folderlist_new();
719
720                 folderlist_pushdir(sfile->folders_prev, sfile->params->dir);
721                 folderlist_popdir(sfile->folders_next, sfile->params->dir);
722
723                 // update folder_prev so we can check for it in folderlist_clear_next()
724                 folderlist_pushdir(sfile->folders_prev, sfile->params->dir);
725
726                 file_change_dir(sfile);
727         }               
728         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
729
730         return OPERATOR_FINISHED;
731 }
732
733 int file_directory_new_exec(bContext *C, wmOperator *unused)
734 {
735         char tmpstr[FILE_MAX];
736         char tmpdir[FILE_MAXFILE];
737         int i = 1;
738
739         SpaceFile *sfile= CTX_wm_space_file(C);
740         
741         if(sfile->params) {
742                  
743                 BLI_strncpy(tmpstr, sfile->params->dir, FILE_MAX);
744                 BLI_join_dirfile(tmpstr, tmpstr, "New Folder");
745                 while (BLI_exists(tmpstr)) {
746                         BLI_snprintf(tmpdir, FILE_MAXFILE, "New Folder(%d)", i++);
747                         BLI_strncpy(tmpstr, sfile->params->dir, FILE_MAX);
748                         BLI_join_dirfile(tmpstr, tmpstr, tmpdir);
749                 }
750                 BLI_recurdir_fileops(tmpstr);
751                 if (BLI_exists(tmpstr)) {
752                         BLI_strncpy(sfile->params->renamefile, tmpdir, FILE_MAXFILE);
753                 } else {
754                         filelist_free(sfile->files);
755                         filelist_parent(sfile->files);
756                         BLI_strncpy(sfile->params->dir, filelist_dir(sfile->files), FILE_MAX);
757                 } 
758         }               
759         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
760
761         return OPERATOR_FINISHED;
762 }
763
764
765 void FILE_OT_directory_new(struct wmOperatorType *ot)
766 {
767         /* identifiers */
768         ot->name= "Create New Directory";
769         ot->idname= "FILE_OT_directory_new";
770         ot->description= "Create a new directory";
771         
772         /* api callbacks */
773         ot->invoke= WM_operator_confirm;
774         ot->exec= file_directory_new_exec;
775         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
776 }
777
778 int file_directory_exec(bContext *C, wmOperator *unused)
779 {
780         char tmpstr[FILE_MAX];
781
782         SpaceFile *sfile= CTX_wm_space_file(C);
783         
784         if(sfile->params) {
785
786                 if ( sfile->params->dir[0] == '~' ) {
787                         if (sfile->params->dir[1] == '\0') {
788                                 BLI_strncpy(sfile->params->dir, BLI_gethome(), sizeof(sfile->params->dir) );
789                         } else {
790                                 /* replace ~ with home */
791                                 char homestr[FILE_MAX];
792                                 char *d = &sfile->params->dir[1];
793
794                                 while ( (*d == '\\') || (*d == '/') )
795                                         d++;
796                                 BLI_strncpy(homestr,  BLI_gethome(), FILE_MAX);
797                                 BLI_join_dirfile(tmpstr, homestr, d);
798                                 BLI_strncpy(sfile->params->dir, tmpstr, sizeof(sfile->params->dir));
799                         }
800                 }
801 #ifdef WIN32
802                 if (sfile->params->dir[0] == '\0')
803                         get_default_root(sfile->params->dir);
804 #endif
805                 BLI_cleanup_dir(G.sce, sfile->params->dir);
806                 BLI_add_slash(sfile->params->dir);
807                 file_change_dir(sfile);
808                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
809         }               
810         
811
812         return OPERATOR_FINISHED;
813 }
814
815 int file_filename_exec(bContext *C, wmOperator *unused)
816 {
817         SpaceFile *sfile= CTX_wm_space_file(C);
818         
819         if(sfile->params) {
820                 if (file_select_match(sfile, sfile->params->file))
821                 {
822                         sfile->params->file[0] = '\0';
823                         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_PARAMS, NULL);
824                 }
825         }               
826
827         return OPERATOR_FINISHED;
828 }
829
830
831 void FILE_OT_refresh(struct wmOperatorType *ot)
832 {
833         /* identifiers */
834         ot->name= "Refresh Filelist";
835         ot->idname= "FILE_OT_refresh";
836         
837         /* api callbacks */
838         ot->exec= file_refresh_exec;
839         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
840 }
841
842 int file_hidedot_exec(bContext *C, wmOperator *unused)
843 {
844         SpaceFile *sfile= CTX_wm_space_file(C);
845         
846         if(sfile->params) {
847                 sfile->params->flag ^= FILE_HIDE_DOT;
848                 filelist_free(sfile->files);
849                 sfile->params->active_file = -1;
850                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
851         }
852         
853         return OPERATOR_FINISHED;
854
855 }
856
857
858 void FILE_OT_hidedot(struct wmOperatorType *ot)
859 {
860         /* identifiers */
861         ot->name= "Toggle Hide Dot Files";
862         ot->idname= "FILE_OT_hidedot";
863         
864         /* api callbacks */
865         ot->exec= file_hidedot_exec;
866         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
867 }
868
869 struct ARegion *file_buttons_region(struct ScrArea *sa)
870 {
871         ARegion *ar, *arnew;
872         
873         for(ar= sa->regionbase.first; ar; ar= ar->next)
874                 if(ar->regiontype==RGN_TYPE_CHANNELS)
875                         return ar;
876
877         /* add subdiv level; after header */
878         for(ar= sa->regionbase.first; ar; ar= ar->next)
879                 if(ar->regiontype==RGN_TYPE_HEADER)
880                         break;
881         
882         /* is error! */
883         if(ar==NULL) return NULL;
884         
885         arnew= MEM_callocN(sizeof(ARegion), "buttons for file panels");
886         
887         BLI_insertlinkafter(&sa->regionbase, ar, arnew);
888         arnew->regiontype= RGN_TYPE_CHANNELS;
889         arnew->alignment= RGN_ALIGN_LEFT;
890         
891         arnew->flag = RGN_FLAG_HIDDEN;
892         
893         return arnew;
894 }
895
896 int file_bookmark_toggle_exec(bContext *C, wmOperator *unused)
897 {
898         ScrArea *sa= CTX_wm_area(C);
899         ARegion *ar= file_buttons_region(sa);
900         
901         if(ar)
902                 ED_region_toggle_hidden(C, ar);
903
904         return OPERATOR_FINISHED;
905 }
906
907 void FILE_OT_bookmark_toggle(struct wmOperatorType *ot)
908 {
909         /* identifiers */
910         ot->name= "Toggle Bookmarks";
911         ot->idname= "FILE_OT_bookmark_toggle";
912         
913         /* api callbacks */
914         ot->exec= file_bookmark_toggle_exec;
915         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
916 }
917
918
919 int file_filenum_exec(bContext *C, wmOperator *op)
920 {
921         SpaceFile *sfile= CTX_wm_space_file(C);
922         ScrArea *sa= CTX_wm_area(C);
923         
924         int inc = RNA_int_get(op->ptr, "increment");
925         if(sfile->params && (inc != 0)) {
926                 BLI_newname(sfile->params->file, inc);
927                 ED_area_tag_redraw(sa);
928                 // WM_event_add_notifier(C, NC_WINDOW, NULL);
929         }
930         
931         return OPERATOR_FINISHED;
932
933 }
934
935 void FILE_OT_filenum(struct wmOperatorType *ot)
936 {
937         /* identifiers */
938         ot->name= "Increment Number in Filename";
939         ot->idname= "FILE_OT_filenum";
940         
941         /* api callbacks */
942         ot->exec= file_filenum_exec;
943         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
944
945         /* props */
946         RNA_def_int(ot->srna, "increment", 1, 0, 100, "Increment", "", 0,100);
947 }
948
949 int file_rename_exec(bContext *C, wmOperator *op)
950 {
951         ScrArea *sa= CTX_wm_area(C);
952         SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
953         
954         if(sfile->params) {
955                 int idx = sfile->params->active_file;
956                 int numfiles = filelist_numfiles(sfile->files);
957                 if ( (0<=idx) && (idx<numfiles) ) {
958                         struct direntry *file= filelist_file(sfile->files, idx);
959                         file->flags |= EDITING;
960                 }
961                 ED_area_tag_redraw(sa);
962         }
963         
964         return OPERATOR_FINISHED;
965
966 }
967
968 int file_rename_poll(bContext *C)
969 {
970         int poll = ED_operator_file_active(C);
971         SpaceFile *sfile= CTX_wm_space_file(C);
972
973         if (sfile && sfile->params) {
974                 if (sfile->params->active_file < 0) { 
975                         poll= 0;
976                 } else {
977                         char dir[FILE_MAX], group[FILE_MAX];    
978                         if (filelist_islibrary(sfile->files, dir, group)) poll= 0;
979                 }
980         }
981         else
982                 poll= 0;
983         return poll;
984 }
985
986 void FILE_OT_rename(struct wmOperatorType *ot)
987 {
988         /* identifiers */
989         ot->name= "Rename File or Directory";
990         ot->idname= "FILE_OT_rename";
991         
992         /* api callbacks */
993         ot->exec= file_rename_exec;
994         ot->poll= file_rename_poll; 
995
996 }
997
998 int file_delete_poll(bContext *C)
999 {
1000         int poll = ED_operator_file_active(C);
1001         SpaceFile *sfile= CTX_wm_space_file(C);
1002         struct direntry* file;
1003
1004         if (sfile && sfile->params) {
1005                 if (sfile->params->active_file < 0) { 
1006                         poll= 0;
1007                 } else {
1008                         char dir[FILE_MAX], group[FILE_MAX];    
1009                         if (filelist_islibrary(sfile->files, dir, group)) poll= 0;
1010                         file = filelist_file(sfile->files, sfile->params->active_file);
1011                         if (file && S_ISDIR(file->type)) poll= 0;
1012                 }
1013         }
1014         else
1015                 poll= 0;
1016                 
1017         return poll;
1018 }
1019
1020 int file_delete_exec(bContext *C, wmOperator *op)
1021 {
1022         char str[FILE_MAX];
1023         SpaceFile *sfile= CTX_wm_space_file(C);
1024         struct direntry* file;
1025         
1026         
1027         file = filelist_file(sfile->files, sfile->params->active_file);
1028         BLI_make_file_string(G.sce, str, sfile->params->dir, file->relname);
1029         BLI_delete(str, 0, 0);  
1030         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
1031         
1032         return OPERATOR_FINISHED;
1033
1034 }
1035
1036 void FILE_OT_delete(struct wmOperatorType *ot)
1037 {
1038         /* identifiers */
1039         ot->name= "Delete File";
1040         ot->idname= "FILE_OT_delete";
1041         
1042         /* api callbacks */
1043         ot->invoke= WM_operator_confirm;
1044         ot->exec= file_delete_exec;
1045         ot->poll= file_delete_poll; /* <- important, handler is on window level */
1046 }
1047