2.5 file browser
[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, short clamp)
72 {
73         float fx,fy;
74         int active_file = -1;
75         int numfiles = filelist_numfiles(sfile->files);
76         View2D* v2d = &ar->v2d;
77
78         UI_view2d_region_to_view(v2d, x, y, &fx, &fy);
79
80         active_file = ED_fileselect_layout_offset(sfile->layout, v2d->tot.xmin + fx, v2d->tot.ymax - fy);
81
82         if(active_file < 0) {
83                 if(clamp)       active_file=  0;
84                 else            active_file= -1;
85         }
86         else if(active_file >= numfiles) {
87                 if(clamp)       active_file=  numfiles-1;
88                 else            active_file= -1;
89         }
90         
91         return active_file;
92 }
93
94
95 static void file_deselect_all(SpaceFile* sfile)
96 {
97         int numfiles = filelist_numfiles(sfile->files);
98         int i;
99
100         for ( i=0; i < numfiles; ++i) {
101                 struct direntry* file = filelist_file(sfile->files, i);
102                 if (file && (file->flags & ACTIVE)) {
103                         file->flags &= ~ACTIVE;
104                 }
105         }
106 }
107
108 typedef enum FileSelect { FILE_SELECT_DIR = 1, 
109   FILE_SELECT_FILE = 2 } FileSelect;
110
111
112 static FileSelect file_select(SpaceFile* sfile, ARegion* ar, const rcti* rect, short val)
113 {
114         int first_file = -1;
115         int last_file = -1;
116         int act_file;
117         short selecting = (val == LEFTMOUSE);
118         FileSelect retval = FILE_SELECT_FILE;
119
120         FileSelectParams *params = ED_fileselect_get_params(sfile);
121         // FileLayout *layout = ED_fileselect_get_layout(sfile, ar);
122
123         int numfiles = filelist_numfiles(sfile->files);
124
125         params->selstate = NOTACTIVE;
126         first_file = find_file_mouse(sfile, ar, rect->xmin, rect->ymax, 1);
127         last_file = find_file_mouse(sfile, ar, rect->xmax, rect->ymin, 1);
128         
129         /* select all valid files between first and last indicated */
130         if ( (first_file >= 0) && (first_file < numfiles) && (last_file >= 0) && (last_file < numfiles) ) {
131                 for (act_file = first_file; act_file <= last_file; act_file++) {
132                         struct direntry* file = filelist_file(sfile->files, act_file);
133                         if (selecting) 
134                                 file->flags |= ACTIVE;
135                         else
136                                 file->flags &= ~ACTIVE;
137                 }
138         }
139
140         /* make the last file active */
141         if (selecting && (last_file >= 0 && last_file < numfiles)) {
142                 struct direntry* file = filelist_file(sfile->files, last_file);
143                 params->active_file = last_file;
144
145                 if(file && S_ISDIR(file->type)) {
146                         /* the path is too long! */
147                         if (strlen(params->dir) + strlen(file->relname) >= FILE_MAX ) 
148                         {
149                                 // XXX error("Path too long, cannot enter this directory");
150                         } else {
151                                 BLI_cleanup_dir(G.sce, params->dir);
152                                 strcat(params->dir, file->relname);
153                                 BLI_add_slash(params->dir);
154                                 params->file[0] = '\0';
155                                 file_change_dir(sfile);
156                                 retval = FILE_SELECT_DIR;
157                         }
158                 }
159                 else if (file)
160                 {
161                         if (file->relname) {
162                                 BLI_strncpy(params->file, file->relname, FILE_MAXFILE);
163                         }
164                         
165                 }       
166         }
167         return retval;
168 }
169
170
171
172 static int file_border_select_exec(bContext *C, wmOperator *op)
173 {
174         ARegion *ar= CTX_wm_region(C);
175         SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
176         short val;
177         rcti rect;
178
179         val= RNA_int_get(op->ptr, "event_type");
180         rect.xmin= RNA_int_get(op->ptr, "xmin");
181         rect.ymin= RNA_int_get(op->ptr, "ymin");
182         rect.xmax= RNA_int_get(op->ptr, "xmax");
183         rect.ymax= RNA_int_get(op->ptr, "ymax");
184
185         BLI_isect_rcti(&(ar->v2d.mask), &rect, &rect);
186         
187         if (FILE_SELECT_DIR == file_select(sfile, ar, &rect, val )) {
188                 WM_event_add_notifier(C, NC_FILE|ND_FILELIST, NULL);
189         } else {
190                 WM_event_add_notifier(C, NC_FILE|ND_PARAMS, NULL);
191         }
192         return OPERATOR_FINISHED;
193 }
194
195 void FILE_OT_select_border(wmOperatorType *ot)
196 {
197         /* identifiers */
198         ot->name= "Activate/Select File";
199         ot->idname= "FILE_OT_select_border";
200         
201         /* api callbacks */
202         ot->invoke= WM_border_select_invoke;
203         ot->exec= file_border_select_exec;
204         ot->modal= WM_border_select_modal;
205
206         /* rna */
207         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
208         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
209         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
210         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
211         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
212
213         ot->poll= ED_operator_file_active;
214 }
215
216 static int file_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
217 {
218         ARegion *ar= CTX_wm_region(C);
219         SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
220         short val;
221         rcti rect;
222
223         rect.xmin = rect.xmax = event->x - ar->winrct.xmin;
224         rect.ymin = rect.ymax = event->y - ar->winrct.ymin;
225         val = event->val;
226
227         if (BLI_in_rcti(&ar->v2d.mask, rect.xmin, rect.ymin)) { 
228
229                 /* single select, deselect all selected first */
230                 file_deselect_all(sfile);
231                 if (FILE_SELECT_DIR == file_select(sfile, ar, &rect, val )) {
232                         WM_event_add_notifier(C, NC_FILE|ND_FILELIST, NULL);
233                 } else {
234                         WM_event_add_notifier(C, NC_FILE|ND_PARAMS, NULL);
235                 }
236         }
237         return OPERATOR_FINISHED;
238 }
239
240 void FILE_OT_select(wmOperatorType *ot)
241 {
242         /* identifiers */
243         ot->name= "Activate/Select File";
244         ot->idname= "FILE_OT_select";
245         
246         /* api callbacks */
247         ot->invoke= file_select_invoke;
248
249         /* rna */
250
251         ot->poll= ED_operator_file_active;
252 }
253
254 static int file_select_all_invoke(bContext *C, wmOperator *op, wmEvent *event)
255 {
256         ScrArea *sa= CTX_wm_area(C);
257         SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
258         int numfiles = filelist_numfiles(sfile->files);
259         int i;
260         int select = 1;
261
262         /* if any file is selected, deselect all first */
263         for ( i=0; i < numfiles; ++i) {
264                 struct direntry* file = filelist_file(sfile->files, i);
265                 if (file && (file->flags & ACTIVE)) {
266                         file->flags &= ~ACTIVE;
267                         select = 0;
268                         ED_area_tag_redraw(sa);
269                 }
270         }
271         /* select all only if previously no file was selected */
272         if (select) {
273                 for ( i=0; i < numfiles; ++i) {
274                         struct direntry* file = filelist_file(sfile->files, i);
275                         if(file && !S_ISDIR(file->type)) {
276                                 file->flags |= ACTIVE;
277                                 ED_area_tag_redraw(sa);
278                         }
279                 }
280         }
281         return OPERATOR_FINISHED;
282 }
283
284 void FILE_OT_select_all_toggle(wmOperatorType *ot)
285 {
286         /* identifiers */
287         ot->name= "Select/Deselect all files";
288         ot->idname= "FILE_OT_select_all_toggle";
289         
290         /* api callbacks */
291         ot->invoke= file_select_all_invoke;
292
293         /* rna */
294
295         ot->poll= ED_operator_file_active;
296 }
297
298 /* ---------- BOOKMARKS ----------- */
299
300 static int bookmark_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
301 {
302         SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
303
304         if(RNA_struct_find_property(op->ptr, "dir")) {
305                 char entry[256];
306                 FileSelectParams* params = sfile->params;
307
308                 RNA_string_get(op->ptr, "dir", entry);
309                 BLI_strncpy(params->dir, entry, sizeof(params->dir));
310                 BLI_cleanup_dir(G.sce, params->dir);
311                 file_change_dir(sfile);                         
312                 params->file[0] = '\0';
313
314                 WM_event_add_notifier(C, NC_FILE|ND_FILELIST, NULL);
315         }
316         
317         return OPERATOR_FINISHED;
318 }
319
320 void FILE_OT_select_bookmark(wmOperatorType *ot)
321 {
322         /* identifiers */
323         ot->name= "Select Directory";
324         ot->idname= "FILE_OT_select_bookmark";
325         
326         /* api callbacks */
327         ot->invoke= bookmark_select_invoke;
328         ot->poll= ED_operator_file_active;
329
330         RNA_def_string(ot->srna, "dir", "", 256, "Dir", "");
331 }
332
333 static int bookmark_add_invoke(bContext *C, wmOperator *op, wmEvent *event)
334 {
335         ScrArea *sa= CTX_wm_area(C);
336         SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
337         struct FSMenu* fsmenu = fsmenu_get();
338         struct FileSelectParams* params= ED_fileselect_get_params(sfile);
339
340         if (params->dir[0] != '\0') {
341                 char name[FILE_MAX];
342         
343                 fsmenu_insert_entry(fsmenu, FS_CATEGORY_BOOKMARKS, params->dir, 0, 1);
344                 BLI_make_file_string("/", name, BLI_gethome(), ".Bfs");
345                 fsmenu_write_file(fsmenu, name);
346         }
347
348         ED_area_tag_redraw(sa);
349         return OPERATOR_FINISHED;
350 }
351
352 void FILE_OT_add_bookmark(wmOperatorType *ot)
353 {
354         /* identifiers */
355         ot->name= "Add Bookmark";
356         ot->idname= "FILE_OT_add_bookmark";
357         
358         /* api callbacks */
359         ot->invoke= bookmark_add_invoke;
360         ot->poll= ED_operator_file_active;
361 }
362
363 static int bookmark_delete_invoke(bContext *C, wmOperator *op, wmEvent *event)
364 {
365         ScrArea *sa= CTX_wm_area(C);
366         struct FSMenu* fsmenu = fsmenu_get();
367         int nentries = fsmenu_get_nentries(fsmenu, FS_CATEGORY_BOOKMARKS);
368         
369         if(RNA_struct_find_property(op->ptr, "index")) {
370                 int index = RNA_int_get(op->ptr, "index");
371                 if ( (index >-1) && (index < nentries)) {
372                         char name[FILE_MAX];
373                         
374                         fsmenu_remove_entry(fsmenu, FS_CATEGORY_BOOKMARKS, index);
375                         BLI_make_file_string("/", name, BLI_gethome(), ".Bfs");
376                         fsmenu_write_file(fsmenu, name);
377                         ED_area_tag_redraw(sa);
378                 }
379         }
380
381         return OPERATOR_FINISHED;
382 }
383
384 void FILE_OT_delete_bookmark(wmOperatorType *ot)
385 {
386         /* identifiers */
387         ot->name= "Delete Bookmark";
388         ot->idname= "FILE_OT_delete_bookmark";
389         
390         /* api callbacks */
391         ot->invoke= bookmark_delete_invoke;
392         ot->poll= ED_operator_file_active;
393
394         RNA_def_int(ot->srna, "index", -1, -1, 20000, "Index", "", -1, 20000);
395 }
396
397
398 static int loadimages_invoke(bContext *C, wmOperator *op, wmEvent *event)
399 {
400         ScrArea *sa= CTX_wm_area(C);
401         SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
402         if (sfile->files) {
403                 filelist_loadimage_timer(sfile->files);
404                 if (filelist_changed(sfile->files)) {
405                         ED_area_tag_redraw(sa);
406                 }
407         }
408
409         return OPERATOR_FINISHED;
410 }
411
412 void FILE_OT_loadimages(wmOperatorType *ot)
413 {
414         
415         /* identifiers */
416         ot->name= "Load Images";
417         ot->idname= "FILE_OT_loadimages";
418         
419         /* api callbacks */
420         ot->invoke= loadimages_invoke;
421         
422         ot->poll= ED_operator_file_active;
423 }
424
425 int file_hilight_set(SpaceFile *sfile, ARegion *ar, int mx, int my)
426 {
427         FileSelectParams* params;
428         int numfiles, actfile;
429         
430         if(sfile==NULL || sfile->files==NULL) return 0;
431         
432         numfiles = filelist_numfiles(sfile->files);
433         params = ED_fileselect_get_params(sfile);
434
435         actfile = find_file_mouse(sfile, ar, mx , my, 0);
436         
437         if (params && (actfile >= 0) && (actfile < numfiles) ) {
438                 params->active_file=actfile;
439                 return 1;
440         } 
441         params->active_file= -1;
442         return 0;
443 }
444
445 static int file_highlight_invoke(bContext *C, wmOperator *op, wmEvent *event)
446 {
447         ARegion *ar= CTX_wm_region(C);
448         SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
449         
450         if( file_hilight_set(sfile, ar, event->x - ar->winrct.xmin, event->y - ar->winrct.ymin)) {
451                 ED_area_tag_redraw(CTX_wm_area(C));
452         }
453         
454         return OPERATOR_FINISHED;
455 }
456
457 void FILE_OT_highlight(struct wmOperatorType *ot)
458 {
459         /* identifiers */
460         ot->name= "Highlight File";
461         ot->idname= "FILE_OT_highlight";
462         
463         /* api callbacks */
464         ot->invoke= file_highlight_invoke;
465         ot->poll= ED_operator_file_active;
466 }
467
468 int file_cancel_exec(bContext *C, wmOperator *unused)
469 {
470         SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
471
472         folderlist_free(sfile->folders_prev);
473         folderlist_free(sfile->folders_next);
474
475         WM_event_fileselect_event(C, sfile->op, EVT_FILESELECT_CANCEL);
476         sfile->op = NULL;
477         
478         return OPERATOR_FINISHED;
479 }
480
481 void FILE_OT_cancel(struct wmOperatorType *ot)
482 {
483         /* identifiers */
484         ot->name= "Cancel File Load";
485         ot->idname= "FILE_OT_cancel";
486         
487         /* api callbacks */
488         ot->exec= file_cancel_exec;
489         ot->poll= ED_operator_file_active;
490 }
491
492 /* sends events now, so things get handled on windowqueue level */
493 int file_exec(bContext *C, wmOperator *unused)
494 {
495         SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
496         char name[FILE_MAX];
497         
498         if(sfile->op) {
499                 wmOperator *op= sfile->op;
500                 
501                 sfile->op = NULL;
502                 BLI_strncpy(name, sfile->params->dir, sizeof(name));
503                 strcat(name, sfile->params->file);
504                 RNA_string_set(op->ptr, "filename", name);
505                 
506                 /* some ops have multiple files to select */
507                 {
508                         PointerRNA itemptr;
509                         int i, numfiles = filelist_numfiles(sfile->files);
510                         struct direntry *file;
511                         if(RNA_struct_find_property(op->ptr, "files")) {
512                                 for (i=0; i<numfiles; i++) {
513                                         file = filelist_file(sfile->files, i);
514                                         if(file->flags & ACTIVE) {
515                                                 if ((file->type & S_IFDIR)==0) {
516                                                         RNA_collection_add(op->ptr, "files", &itemptr);
517                                                         RNA_string_set(&itemptr, "name", file->relname);
518                                                 }
519                                         }
520                                 }
521                         }
522                         
523                         if(RNA_struct_find_property(op->ptr, "dirs")) {
524                                 for (i=0; i<numfiles; i++) {
525                                         file = filelist_file(sfile->files, i);
526                                         if(file->flags & ACTIVE) {
527                                                 if ((file->type & S_IFDIR)) {
528                                                         RNA_collection_add(op->ptr, "dirs", &itemptr);
529                                                         RNA_string_set(&itemptr, "name", file->relname);
530                                                 }
531                                         }
532                                 }
533                         }
534                 }
535                 
536                 folderlist_free(sfile->folders_prev);
537                 folderlist_free(sfile->folders_next);
538
539                 fsmenu_insert_entry(fsmenu_get(), FS_CATEGORY_RECENT, sfile->params->dir,0, 1);
540                 BLI_make_file_string(G.sce, name, BLI_gethome(), ".Bfs");
541                 fsmenu_write_file(fsmenu_get(), name);
542                 WM_event_fileselect_event(C, op, EVT_FILESELECT_EXEC);
543         }
544                                 
545         return OPERATOR_FINISHED;
546 }
547
548 void FILE_OT_exec(struct wmOperatorType *ot)
549 {
550         /* identifiers */
551         ot->name= "Execute File Window";
552         ot->idname= "FILE_OT_exec";
553         
554         /* api callbacks */
555         ot->exec= file_exec;
556         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
557 }
558
559
560 int file_parent_exec(bContext *C, wmOperator *unused)
561 {
562         SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
563         
564         if(sfile->params) {
565                 if (BLI_has_parent(sfile->params->dir)) {
566                         BLI_parent_dir(sfile->params->dir);
567                         BLI_cleanup_dir(G.sce, sfile->params->dir);
568                         file_change_dir(sfile);
569                         WM_event_add_notifier(C, NC_FILE|ND_FILELIST, NULL);
570                 }
571         }               
572         
573         return OPERATOR_FINISHED;
574
575 }
576
577
578 void FILE_OT_parent(struct wmOperatorType *ot)
579 {
580         /* identifiers */
581         ot->name= "Parent File";
582         ot->idname= "FILE_OT_parent";
583         
584         /* api callbacks */
585         ot->exec= file_parent_exec;
586         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
587 }
588
589
590 int file_refresh_exec(bContext *C, wmOperator *unused)
591 {
592         SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
593         
594         file_change_dir(sfile);
595
596         WM_event_add_notifier(C, NC_FILE|ND_FILELIST, NULL);
597
598         return OPERATOR_FINISHED;
599
600 }
601
602 void FILE_OT_previous(struct wmOperatorType *ot)
603 {
604         /* identifiers */
605         ot->name= "Previous Folder";
606         ot->idname= "FILE_OT_previous";
607         
608         /* api callbacks */
609         ot->exec= file_previous_exec;
610         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
611 }
612
613 int file_previous_exec(bContext *C, wmOperator *unused)
614 {
615         SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
616
617         if(sfile->params) {
618                 if (!sfile->folders_next)
619                         sfile->folders_next = folderlist_new();
620
621                 folderlist_pushdir(sfile->folders_next, sfile->params->dir);
622                 folderlist_popdir(sfile->folders_prev, sfile->params->dir);
623                 folderlist_pushdir(sfile->folders_next, sfile->params->dir);
624
625                 file_change_dir(sfile);
626         }
627         WM_event_add_notifier(C, NC_FILE|ND_FILELIST, NULL);
628
629         return OPERATOR_FINISHED;
630 }
631
632 void FILE_OT_next(struct wmOperatorType *ot)
633 {
634         /* identifiers */
635         ot->name= "Next Folder";
636         ot->idname= "FILE_OT_next";
637         
638         /* api callbacks */
639         ot->exec= file_next_exec;
640         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
641 }
642
643 int file_next_exec(bContext *C, wmOperator *unused)
644 {
645         SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
646                 if(sfile->params) {
647                         if (!sfile->folders_next)
648                         sfile->folders_next = folderlist_new();
649
650                 folderlist_pushdir(sfile->folders_prev, sfile->params->dir);
651                 folderlist_popdir(sfile->folders_next, sfile->params->dir);
652
653                 // update folder_prev so we can check for it in folderlist_clear_next()
654                 folderlist_pushdir(sfile->folders_prev, sfile->params->dir);
655
656                 file_change_dir(sfile);
657         }               
658         WM_event_add_notifier(C, NC_FILE|ND_FILELIST, NULL);
659
660         return OPERATOR_FINISHED;
661 }
662
663 int file_directory_new_exec(bContext *C, wmOperator *unused)
664 {
665         char tmpstr[FILE_MAX];
666         char tmpdir[FILE_MAXFILE];
667         int i = 1;
668
669         SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
670         
671         if(sfile->params) {
672                  
673                 BLI_strncpy(tmpstr, sfile->params->dir, FILE_MAX);
674                 BLI_join_dirfile(tmpstr, tmpstr, "New Folder");
675                 while (BLI_exists(tmpstr)) {
676                         BLI_snprintf(tmpdir, FILE_MAXFILE, "New Folder(%d)", i++);
677                         BLI_strncpy(tmpstr, sfile->params->dir, FILE_MAX);
678                         BLI_join_dirfile(tmpstr, tmpstr, tmpdir);
679                 }
680                 BLI_recurdir_fileops(tmpstr);
681                 if (!BLI_exists(tmpstr)) {
682                         filelist_free(sfile->files);
683                         filelist_parent(sfile->files);
684                         BLI_strncpy(sfile->params->dir, filelist_dir(sfile->files), FILE_MAX);
685                 } 
686         }               
687         WM_event_add_notifier(C, NC_FILE|ND_FILELIST, NULL);
688
689         return OPERATOR_FINISHED;
690 }
691
692
693 void FILE_OT_directory_new(struct wmOperatorType *ot)
694 {
695         /* identifiers */
696         ot->name= "Create New Directory";
697         ot->idname= "FILE_OT_directory_new";
698         
699         /* api callbacks */
700         ot->invoke= WM_operator_confirm;
701         ot->exec= file_directory_new_exec;
702         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
703 }
704
705 int file_directory_exec(bContext *C, wmOperator *unused)
706 {
707         char tmpstr[FILE_MAX];
708
709         SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
710         
711         if(sfile->params) {
712
713                 if ( sfile->params->dir[0] == '~' ) {
714                         if (sfile->params->dir[1] == '\0') {
715                                 BLI_strncpy(sfile->params->dir, BLI_gethome(), sizeof(sfile->params->dir) );
716                         } else {
717                                 /* replace ~ with home */
718                                 char homestr[FILE_MAX];
719                                 char *d = &sfile->params->dir[1];
720
721                                 while ( (*d == '\\') || (*d == '/') )
722                                         d++;
723                                 BLI_strncpy(homestr,  BLI_gethome(), FILE_MAX);
724                                 BLI_join_dirfile(tmpstr, homestr, d);
725                                 BLI_strncpy(sfile->params->dir, tmpstr, sizeof(sfile->params->dir));
726                         }
727                 }
728 #ifdef WIN32
729                 if (sfile->params->dir[0] == '\0')
730                         get_default_root(sfile->params->dir);
731 #endif
732                 BLI_cleanup_dir(G.sce, sfile->params->dir);
733                 BLI_add_slash(sfile->params->dir);
734                 file_change_dir(sfile);
735                 WM_event_add_notifier(C, NC_FILE|ND_FILELIST, NULL);
736         }               
737         
738
739         return OPERATOR_FINISHED;
740 }
741
742 int file_filename_exec(bContext *C, wmOperator *unused)
743 {
744         SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
745         
746         if(sfile->params) {
747                 if (file_select_match(sfile, sfile->params->file))
748                 {
749                         sfile->params->file[0] = '\0';
750                         WM_event_add_notifier(C, NC_FILE|ND_PARAMS, NULL);
751                 }
752         }               
753
754         return OPERATOR_FINISHED;
755 }
756
757
758 void FILE_OT_refresh(struct wmOperatorType *ot)
759 {
760         /* identifiers */
761         ot->name= "Refresh Filelist";
762         ot->idname= "FILE_OT_refresh";
763         
764         /* api callbacks */
765         ot->exec= file_refresh_exec;
766         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
767 }
768
769 int file_hidedot_exec(bContext *C, wmOperator *unused)
770 {
771         SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
772         
773         if(sfile->params) {
774                 sfile->params->flag ^= FILE_HIDE_DOT;
775                 filelist_free(sfile->files);
776                 sfile->params->active_file = -1;
777                 WM_event_add_notifier(C, NC_FILE|ND_FILELIST, NULL);
778         }
779         
780         return OPERATOR_FINISHED;
781
782 }
783
784
785 void FILE_OT_hidedot(struct wmOperatorType *ot)
786 {
787         /* identifiers */
788         ot->name= "Toggle Hide Dot Files";
789         ot->idname= "FILE_OT_hidedot";
790         
791         /* api callbacks */
792         ot->exec= file_hidedot_exec;
793         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
794 }
795
796 struct ARegion *file_buttons_region(struct ScrArea *sa)
797 {
798         ARegion *ar, *arnew;
799         
800         for(ar= sa->regionbase.first; ar; ar= ar->next)
801                 if(ar->regiontype==RGN_TYPE_CHANNELS)
802                         return ar;
803
804         /* add subdiv level; after header */
805         for(ar= sa->regionbase.first; ar; ar= ar->next)
806                 if(ar->regiontype==RGN_TYPE_HEADER)
807                         break;
808         
809         /* is error! */
810         if(ar==NULL) return NULL;
811         
812         arnew= MEM_callocN(sizeof(ARegion), "buttons for file panels");
813         
814         BLI_insertlinkafter(&sa->regionbase, ar, arnew);
815         arnew->regiontype= RGN_TYPE_CHANNELS;
816         arnew->alignment= RGN_ALIGN_LEFT;
817         
818         arnew->flag = RGN_FLAG_HIDDEN;
819         
820         return arnew;
821 }
822
823 int file_bookmark_toggle_exec(bContext *C, wmOperator *unused)
824 {
825         ScrArea *sa= CTX_wm_area(C);
826         ARegion *ar= file_buttons_region(sa);
827         
828         if(ar) {
829                 ar->flag ^= RGN_FLAG_HIDDEN;
830                 ar->v2d.flag &= ~V2D_IS_INITIALISED; /* XXX should become hide/unhide api? */
831                 
832                 ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa);
833                 ED_area_tag_redraw(sa);
834         }
835         return OPERATOR_FINISHED;
836 }
837
838 void FILE_OT_bookmark_toggle(struct wmOperatorType *ot)
839 {
840         /* identifiers */
841         ot->name= "Toggle Bookmarks";
842         ot->idname= "FILE_OT_bookmark_toggle";
843         
844         /* api callbacks */
845         ot->exec= file_bookmark_toggle_exec;
846         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
847 }
848
849
850 int file_filenum_exec(bContext *C, wmOperator *op)
851 {
852         SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
853         
854         int inc = RNA_int_get(op->ptr, "increment");
855         if(sfile->params && (inc != 0)) {
856                 BLI_newname(sfile->params->file, inc);
857                 WM_event_add_notifier(C, NC_WINDOW, NULL);
858         }
859         
860         return OPERATOR_FINISHED;
861
862 }
863
864 void FILE_OT_filenum(struct wmOperatorType *ot)
865 {
866         /* identifiers */
867         ot->name= "Increment Number in Filename";
868         ot->idname= "FILE_OT_filenum";
869         
870         /* api callbacks */
871         ot->exec= file_filenum_exec;
872         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
873
874         /* props */
875         RNA_def_int(ot->srna, "increment", 1, 0, 100, "Increment", "", 0,100);
876 }
877
878 int file_rename_exec(bContext *C, wmOperator *op)
879 {
880         ScrArea *sa= CTX_wm_area(C);
881         SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
882         
883         if(sfile->params) {
884                 int idx = sfile->params->active_file;
885                 int numfiles = filelist_numfiles(sfile->files);
886                 if ( (0<=idx) && (idx<numfiles) ) {
887                         struct direntry *file= filelist_file(sfile->files, idx);
888                         file->flags |= EDITING;
889                 }
890                 ED_area_tag_redraw(sa);
891         }
892         
893         return OPERATOR_FINISHED;
894
895 }
896
897 void FILE_OT_rename(struct wmOperatorType *ot)
898 {
899         /* identifiers */
900         ot->name= "Rename File or Directory";
901         ot->idname= "FILE_OT_rename";
902         
903         /* api callbacks */
904         ot->exec= file_rename_exec;
905         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
906
907 }
908
909 int file_delete_poll(bContext *C)
910 {
911         int poll = ED_operator_file_active(C);
912         SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
913         struct direntry* file;
914
915         if (sfile->params) {
916                 if (sfile->params->active_file < 0) { 
917                         poll= 0;
918                 } else {
919                         file = filelist_file(sfile->files, sfile->params->active_file);
920                         if (file && S_ISDIR(file->type)) poll= 0;
921                 }
922         }
923         else
924                 poll= 0;
925                 
926         return poll;
927 }
928
929 int file_delete_exec(bContext *C, wmOperator *op)
930 {
931         char str[FILE_MAX];
932         SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
933         struct direntry* file;
934         
935         
936         file = filelist_file(sfile->files, sfile->params->active_file);
937         BLI_make_file_string(G.sce, str, sfile->params->dir, file->relname);
938         BLI_delete(str, 0, 0);  
939         WM_event_add_notifier(C, NC_FILE | ND_FILELIST, NULL);
940         
941         return OPERATOR_FINISHED;
942
943 }
944
945 void FILE_OT_delete(struct wmOperatorType *ot)
946 {
947         /* identifiers */
948         ot->name= "Delete File";
949         ot->idname= "FILE_OT_delete";
950         
951         /* api callbacks */
952         ot->invoke= WM_operator_confirm;
953         ot->exec= file_delete_exec;
954         ot->poll= file_delete_poll; /* <- important, handler is on window level */
955 }
956