Fix #27849: 3D manipulator widget lost on mesh in edge mode.
[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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 /** \file blender/editors/space_file/file_ops.c
30  *  \ingroup spfile
31  */
32
33
34 #include "BKE_context.h"
35 #include "BKE_screen.h"
36 #include "BKE_global.h"
37 #include "BKE_report.h"
38 #include "BKE_main.h"
39
40 #include "BLI_blenlib.h"
41 #include "BLI_utildefines.h"
42 #include "BLI_storage_types.h"
43 #ifdef WIN32
44 #include "BLI_winstuff.h"
45 #endif
46
47 #include "ED_screen.h"
48 #include "ED_fileselect.h"
49
50 #include "MEM_guardedalloc.h"
51
52 #include "RNA_access.h"
53 #include "RNA_define.h"
54
55 #include "UI_view2d.h"
56
57 #include "WM_api.h"
58 #include "WM_types.h"
59
60 #include "file_intern.h"
61 #include "filelist.h"
62 #include "fsmenu.h"
63
64 #include <stdlib.h>
65 #include <string.h>
66 #include <stdio.h>
67
68 /* for events */
69 #define NOTACTIVEFILE                   0
70 #define ACTIVATE                        1
71 #define INACTIVATE                      2
72
73 /* ---------- FILE SELECTION ------------ */
74 static FileSelection find_file_mouse_rect(SpaceFile *sfile, struct ARegion* ar, const rcti* rect)
75 {
76         FileSelection sel;
77         float fxmin,fymin,fxmax, fymax;
78         
79         View2D* v2d = &ar->v2d;
80         rcti rect_view;
81
82         UI_view2d_region_to_view(v2d, rect->xmin, rect->ymin, &fxmin, &fymin);
83         UI_view2d_region_to_view(v2d, rect->xmax, rect->ymax, &fxmax, &fymax);
84
85         BLI_init_rcti(&rect_view, (int)(v2d->tot.xmin + fxmin), (int)(v2d->tot.xmin + fxmax), (int)(v2d->tot.ymax - fymin), (int)(v2d->tot.ymax - fymax));
86
87         sel  = ED_fileselect_layout_offset_rect(sfile->layout, &rect_view);
88         
89         return sel;
90 }
91
92 static void file_deselect_all(SpaceFile* sfile, unsigned int flag)
93 {
94         FileSelection sel;
95         sel.first = 0;
96         sel.last = filelist_numfiles(sfile->files)-1;
97         
98         filelist_select(sfile->files, &sel, FILE_SEL_REMOVE, flag, CHECK_ALL);
99 }
100
101 typedef enum FileSelect { 
102         FILE_SELECT_NOTHING = 0,
103         FILE_SELECT_DIR = 1, 
104         FILE_SELECT_FILE = 2 
105 } FileSelect;
106
107 static void clamp_to_filelist(int numfiles, FileSelection* sel)
108 {
109         /* border select before the first file */
110         if ( (sel->first < 0) && (sel->last >=0 ) ) {
111                 sel->first = 0;
112         }
113         /* don't select if everything is outside filelist */
114         if ( (sel->first >= numfiles) && ((sel->last < 0) || (sel->last >= numfiles)) ) {
115                 sel->first = -1;
116                 sel->last = -1;
117         }
118         
119         /* fix if last file invalid */
120         if ( (sel->first > 0) && (sel->last < 0) )
121                 sel->last = numfiles-1;
122
123         /* clamp */
124         if ( (sel->first >= numfiles) ) {
125                 sel->first = numfiles-1;
126         }
127         if ( (sel->last >= numfiles) ) {
128                 sel->last = numfiles-1;
129         }
130 }
131
132 static FileSelection file_selection_get(bContext* C, const rcti* rect, short fill)
133 {
134         ARegion *ar= CTX_wm_region(C);
135         SpaceFile *sfile= CTX_wm_space_file(C);
136         int numfiles = filelist_numfiles(sfile->files);
137         FileSelection sel;
138
139         sel = find_file_mouse_rect(sfile, ar, rect);
140         if ( !((sel.first == -1) && (sel.last == -1)) ) {
141                 clamp_to_filelist(numfiles, &sel);
142         }
143
144
145         /* if desired, fill the selection up from the last selected file to the current one */
146         if (fill && (sel.last >= 0) && (sel.last < numfiles) ) {
147                 int f= sel.last;
148                 while (f >= 0) {
149                         if ( filelist_is_selected(sfile->files, f, CHECK_ALL) )
150                                 break;
151                         f--;
152                 }
153                 if (f >= 0) {
154                         sel.first = f+1;
155                 }
156         }
157         return sel;
158 }
159
160 static FileSelect file_select_do(bContext* C, int selected_idx)
161 {
162         FileSelect retval = FILE_SELECT_NOTHING;
163         SpaceFile *sfile= CTX_wm_space_file(C);
164         FileSelectParams *params = ED_fileselect_get_params(sfile);
165         int numfiles = filelist_numfiles(sfile->files);
166
167         /* make the selected file active */
168         if ( (selected_idx >= 0) && (selected_idx < numfiles)) {
169                 struct direntry* file = filelist_file(sfile->files, selected_idx);
170                 params->active_file = selected_idx;
171
172                 if(file && S_ISDIR(file->type)) {
173                         /* the path is too long and we are not going up! */
174                         if (strcmp(file->relname, "..") && strlen(params->dir) + strlen(file->relname) >= FILE_MAX ) 
175                         {
176                                 // XXX error("Path too long, cannot enter this directory");
177                         } else {
178                                 if (strcmp(file->relname, "..")==0) {    
179                                         /* avoids /../../ */     
180                                         BLI_parent_dir(params->dir);     
181                                 } else {
182                                         BLI_cleanup_dir(G.main->name, params->dir);
183                                         strcat(params->dir, file->relname);
184                                         BLI_add_slash(params->dir);
185                                 }
186
187                                 file_change_dir(C, 0);
188                                 retval = FILE_SELECT_DIR;
189                         }
190                 }
191                 else if (file)
192                 {
193                         if (file->relname) {
194                                 BLI_strncpy(params->file, file->relname, FILE_MAXFILE);
195                         }
196                         retval = FILE_SELECT_FILE;
197                 }
198         }
199         return retval;
200 }
201
202
203 static FileSelect file_select(bContext* C, const rcti* rect, FileSelType select, short fill)
204 {
205         SpaceFile *sfile= CTX_wm_space_file(C);
206         FileSelect retval = FILE_SELECT_NOTHING;
207         FileSelection sel= file_selection_get(C, rect, fill); /* get the selection */
208         const FileCheckType check_type= (sfile->params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : CHECK_ALL;
209         
210         /* flag the files as selected in the filelist */
211         filelist_select(sfile->files, &sel, select, SELECTED_FILE, check_type);
212         
213         /* Don't act on multiple selected files */
214         if (sel.first != sel.last) select = 0;
215
216         /* Do we have a valid selection and are we actually selecting */
217         if ( (sel.last >= 0) && ((select == FILE_SEL_ADD) || (select == FILE_SEL_TOGGLE)) )
218         {
219                 /* Check last selection, if selected, act on the file or dir */
220                 if (filelist_is_selected(sfile->files, sel.last, check_type)) {
221                         retval = file_select_do(C, sel.last);
222                 }
223         }
224
225         /* update operator for name change event */
226         file_draw_check_cb(C, NULL, NULL);
227         
228         return retval;
229 }
230
231 static int file_border_select_modal(bContext *C, wmOperator *op, wmEvent *event)
232 {
233         ARegion *ar= CTX_wm_region(C);
234         SpaceFile *sfile= CTX_wm_space_file(C);
235         FileSelectParams *params = ED_fileselect_get_params(sfile);
236         FileSelection sel;
237         rcti rect;
238
239         int result;
240
241         result= WM_border_select_modal(C, op, event);
242
243         if(result==OPERATOR_RUNNING_MODAL)      {
244
245                 rect.xmin= RNA_int_get(op->ptr, "xmin");
246                 rect.ymin= RNA_int_get(op->ptr, "ymin");
247                 rect.xmax= RNA_int_get(op->ptr, "xmax");
248                 rect.ymax= RNA_int_get(op->ptr, "ymax");
249
250                 BLI_isect_rcti(&(ar->v2d.mask), &rect, &rect);
251
252                 sel = file_selection_get(C, &rect, 0);
253                 if ( (sel.first != params->sel_first) || (sel.last != params->sel_last) ) {
254                         file_deselect_all(sfile, HILITED_FILE);
255                         filelist_select(sfile->files, &sel, FILE_SEL_ADD, HILITED_FILE, CHECK_ALL);
256                         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_PARAMS, NULL);
257                 }
258                 params->sel_first = sel.first; params->sel_last = sel.last;
259
260         }else {
261                 params->active_file = -1;
262                 params->sel_first = params->sel_last = -1;
263                 file_deselect_all(sfile, HILITED_FILE);
264                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_PARAMS, NULL);
265         }
266
267         return result;
268 }
269
270 static int file_border_select_exec(bContext *C, wmOperator *op)
271 {
272         ARegion *ar= CTX_wm_region(C);
273         rcti rect;
274         FileSelect ret;
275
276         short select= (RNA_int_get(op->ptr, "gesture_mode")==GESTURE_MODAL_SELECT);
277         rect.xmin= RNA_int_get(op->ptr, "xmin");
278         rect.ymin= RNA_int_get(op->ptr, "ymin");
279         rect.xmax= RNA_int_get(op->ptr, "xmax");
280         rect.ymax= RNA_int_get(op->ptr, "ymax");
281
282         BLI_isect_rcti(&(ar->v2d.mask), &rect, &rect);
283
284         ret = file_select(C, &rect, select ? FILE_SEL_ADD : FILE_SEL_REMOVE, 0);
285         if (FILE_SELECT_DIR == ret) {
286                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
287         } else if (FILE_SELECT_FILE == ret) {
288                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_PARAMS, NULL);
289         }
290         return OPERATOR_FINISHED;
291 }
292
293 void FILE_OT_select_border(wmOperatorType *ot)
294 {
295         /* identifiers */
296         ot->name= "Activate/Select File";
297         ot->description= "Activate/select the file(s) contained in the border";
298         ot->idname= "FILE_OT_select_border";
299         
300         /* api callbacks */
301         ot->invoke= WM_border_select_invoke;
302         ot->exec= file_border_select_exec;
303         ot->modal= file_border_select_modal;
304         ot->poll= ED_operator_file_active;
305         ot->cancel= WM_border_select_cancel;
306
307         /* rna */
308         WM_operator_properties_gesture_border(ot, 0);
309 }
310
311 static int file_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
312 {
313         ARegion *ar= CTX_wm_region(C);
314         SpaceFile *sfile= CTX_wm_space_file(C);
315         FileSelect ret;
316         rcti rect;
317         int extend = RNA_boolean_get(op->ptr, "extend");
318         int fill = RNA_boolean_get(op->ptr, "fill");
319
320         if(ar->regiontype != RGN_TYPE_WINDOW)
321                 return OPERATOR_CANCELLED;
322
323         rect.xmin = rect.xmax = event->mval[0];
324         rect.ymin = rect.ymax = event->mval[1];
325
326         if(!BLI_in_rcti(&ar->v2d.mask, rect.xmin, rect.ymin))
327                 return OPERATOR_CANCELLED;
328
329         /* single select, deselect all selected first */
330         if (!extend) file_deselect_all(sfile, SELECTED_FILE);
331
332         ret = file_select(C, &rect, extend ? FILE_SEL_TOGGLE : FILE_SEL_ADD, fill);
333         if (FILE_SELECT_DIR == ret)
334                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
335         else if (FILE_SELECT_FILE == ret)
336                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_PARAMS, NULL);
337
338         WM_event_add_mousemove(C); /* for directory changes */
339         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_PARAMS, NULL);
340
341         return OPERATOR_FINISHED;
342 }
343
344 void FILE_OT_select(wmOperatorType *ot)
345 {
346         /* identifiers */
347         ot->name= "Activate/Select File";
348         ot->description= "Activate/select file";
349         ot->idname= "FILE_OT_select";
350         
351         /* api callbacks */
352         ot->invoke= file_select_invoke;
353         ot->poll= ED_operator_file_active;
354
355         /* rna */
356         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first.");
357         RNA_def_boolean(ot->srna, "fill", 0, "Fill", "Select everything beginning with the last selection.");
358 }
359
360 static int file_select_all_exec(bContext *C, wmOperator *UNUSED(op))
361 {
362         ScrArea *sa= CTX_wm_area(C);
363         SpaceFile *sfile= CTX_wm_space_file(C);
364         FileSelection sel;
365         int numfiles = filelist_numfiles(sfile->files);
366         int i;
367         int is_selected = 0;
368
369         sel.first = 0; 
370         sel.last = numfiles-1;
371
372         /* Is any file selected ? */
373         for ( i=0; i < numfiles; ++i) {
374                 if (filelist_is_selected(sfile->files, i, CHECK_ALL)) {
375                         is_selected = 1;
376                         break;
377                 }
378         }
379         /* select all only if previously no file was selected */
380         if (is_selected) {
381                 filelist_select(sfile->files, &sel, FILE_SEL_REMOVE, SELECTED_FILE, CHECK_ALL);
382         }
383         else {
384                 const FileCheckType check_type= (sfile->params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : CHECK_FILES;
385                 filelist_select(sfile->files, &sel, FILE_SEL_ADD, SELECTED_FILE, check_type);
386         }
387         ED_area_tag_redraw(sa);
388         return OPERATOR_FINISHED;
389 }
390
391 void FILE_OT_select_all_toggle(wmOperatorType *ot)
392 {
393         /* identifiers */
394         ot->name= "Select/Deselect All Files";
395         ot->description= "Select/deselect all files";
396         ot->idname= "FILE_OT_select_all_toggle";
397         
398         /* api callbacks */
399         ot->exec= file_select_all_exec;
400         ot->poll= ED_operator_file_active;
401
402         /* rna */
403
404         
405 }
406
407 /* ---------- BOOKMARKS ----------- */
408
409 static int bookmark_select_exec(bContext *C, wmOperator *op)
410 {
411         SpaceFile *sfile= CTX_wm_space_file(C);
412
413         if(RNA_struct_find_property(op->ptr, "dir")) {
414                 char entry[256];
415                 FileSelectParams* params = sfile->params;
416
417                 RNA_string_get(op->ptr, "dir", entry);
418                 BLI_strncpy(params->dir, entry, sizeof(params->dir));
419                 BLI_cleanup_dir(G.main->name, params->dir);
420                 file_change_dir(C, 1);
421
422                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
423         }
424         
425         return OPERATOR_FINISHED;
426 }
427
428 void FILE_OT_select_bookmark(wmOperatorType *ot)
429 {
430         /* identifiers */
431         ot->name= "Select Directory";
432         ot->description= "Select a bookmarked directory";
433         ot->idname= "FILE_OT_select_bookmark";
434         
435         /* api callbacks */
436         ot->exec= bookmark_select_exec;
437         ot->poll= ED_operator_file_active;
438
439         RNA_def_string(ot->srna, "dir", "", 256, "Dir", "");
440 }
441
442 static int bookmark_add_exec(bContext *C, wmOperator *UNUSED(op))
443 {
444         ScrArea *sa= CTX_wm_area(C);
445         SpaceFile *sfile= CTX_wm_space_file(C);
446         struct FSMenu* fsmenu = fsmenu_get();
447         struct FileSelectParams* params= ED_fileselect_get_params(sfile);
448
449         if (params->dir[0] != '\0') {
450                 char name[FILE_MAX];
451         
452                 fsmenu_insert_entry(fsmenu, FS_CATEGORY_BOOKMARKS, params->dir, 0, 1);
453                 BLI_make_file_string("/", name, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
454                 fsmenu_write_file(fsmenu, name);
455         }
456
457         ED_area_tag_redraw(sa);
458         return OPERATOR_FINISHED;
459 }
460
461 void FILE_OT_bookmark_add(wmOperatorType *ot)
462 {
463         /* identifiers */
464         ot->name= "Add Bookmark";
465         ot->description= "Add a bookmark for the selected/active directory";
466         ot->idname= "FILE_OT_bookmark_add";
467         
468         /* api callbacks */
469         ot->exec= bookmark_add_exec;
470         ot->poll= ED_operator_file_active;
471 }
472
473 static int bookmark_delete_exec(bContext *C, wmOperator *op)
474 {
475         ScrArea *sa= CTX_wm_area(C);
476         struct FSMenu* fsmenu = fsmenu_get();
477         int nentries = fsmenu_get_nentries(fsmenu, FS_CATEGORY_BOOKMARKS);
478         
479         if(RNA_struct_find_property(op->ptr, "index")) {
480                 int index = RNA_int_get(op->ptr, "index");
481                 if ( (index >-1) && (index < nentries)) {
482                         char name[FILE_MAX];
483                         
484                         fsmenu_remove_entry(fsmenu, FS_CATEGORY_BOOKMARKS, index);
485                         BLI_make_file_string("/", name, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
486                         fsmenu_write_file(fsmenu, name);
487                         ED_area_tag_redraw(sa);
488                 }
489         }
490
491         return OPERATOR_FINISHED;
492 }
493
494 void FILE_OT_delete_bookmark(wmOperatorType *ot)
495 {
496         /* identifiers */
497         ot->name= "Delete Bookmark";
498         ot->description= "Delete selected bookmark";
499         ot->idname= "FILE_OT_delete_bookmark";
500         
501         /* api callbacks */
502         ot->exec= bookmark_delete_exec;
503         ot->poll= ED_operator_file_active;
504
505         RNA_def_int(ot->srna, "index", -1, -1, 20000, "Index", "", -1, 20000);
506 }
507
508 int file_hilight_set(SpaceFile *sfile, ARegion *ar, int mx, int my)
509 {
510         View2D* v2d = &ar->v2d;
511         FileSelectParams* params;
512         int numfiles, origfile; 
513
514         if(sfile==NULL || sfile->files==NULL) return 0;
515
516         numfiles = filelist_numfiles(sfile->files);
517         params = ED_fileselect_get_params(sfile);
518
519         origfile= params->active_file;
520
521         mx -= ar->winrct.xmin;
522         my -= ar->winrct.ymin;
523
524         if(BLI_in_rcti(&ar->v2d.mask, mx, my)) {
525                 float fx, fy;
526                 int active_file;
527
528                 UI_view2d_region_to_view(v2d, mx, my, &fx, &fy);
529
530                 active_file = ED_fileselect_layout_offset(sfile->layout, (int)(v2d->tot.xmin + fx), (int)(v2d->tot.ymax - fy));
531
532                 if((active_file >= 0) && (active_file < numfiles))
533                         params->active_file=active_file;
534                 else
535                         params->active_file= -1;
536         }
537         else
538                 params->active_file= -1;
539
540         return (params->active_file != origfile);
541 }
542
543 static int file_highlight_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
544 {
545         ARegion *ar= CTX_wm_region(C);
546         SpaceFile *sfile= CTX_wm_space_file(C);
547
548         if(!file_hilight_set(sfile, ar, event->x, event->y))
549                 return OPERATOR_CANCELLED;
550
551         ED_area_tag_redraw(CTX_wm_area(C));
552         
553         return OPERATOR_FINISHED;
554 }
555
556 void FILE_OT_highlight(struct wmOperatorType *ot)
557 {
558         /* identifiers */
559         ot->name= "Highlight File";
560         ot->description= "Highlight selected file(s)";
561         ot->idname= "FILE_OT_highlight";
562         
563         /* api callbacks */
564         ot->invoke= file_highlight_invoke;
565         ot->poll= ED_operator_file_active;
566 }
567
568 int file_cancel_exec(bContext *C, wmOperator *UNUSED(unused))
569 {
570         SpaceFile *sfile= CTX_wm_space_file(C);
571         wmOperator *op = sfile->op;
572         
573         sfile->op = NULL;
574
575         WM_event_fileselect_event(C, op, EVT_FILESELECT_CANCEL);
576         
577         return OPERATOR_FINISHED;
578 }
579
580 static int file_operator_poll(bContext *C)
581 {
582         int poll = ED_operator_file_active(C);
583         SpaceFile *sfile= CTX_wm_space_file(C);
584
585         if (!sfile || !sfile->op) poll= 0;
586
587         return poll;
588 }
589
590 void FILE_OT_cancel(struct wmOperatorType *ot)
591 {
592         /* identifiers */
593         ot->name= "Cancel File Load";
594         ot->description= "Cancel loading of selected file";
595         ot->idname= "FILE_OT_cancel";
596         
597         /* api callbacks */
598         ot->exec= file_cancel_exec;
599         ot->poll= file_operator_poll;
600 }
601
602
603 void file_sfile_to_operator(wmOperator *op, SpaceFile *sfile, char *filepath)
604 {
605         BLI_join_dirfile(filepath, FILE_MAX, sfile->params->dir, sfile->params->file); /* XXX, not real length */
606         if(RNA_struct_find_property(op->ptr, "relative_path")) {
607                 if(RNA_boolean_get(op->ptr, "relative_path")) {
608                         BLI_path_rel(filepath, G.main->name);
609                 }
610         }
611
612         if(RNA_struct_find_property(op->ptr, "filename")) {
613                 RNA_string_set(op->ptr, "filename", sfile->params->file);
614         }
615         if(RNA_struct_find_property(op->ptr, "directory")) {
616                 RNA_string_set(op->ptr, "directory", sfile->params->dir);
617         }
618         if(RNA_struct_find_property(op->ptr, "filepath")) {
619                 RNA_string_set(op->ptr, "filepath", filepath);
620         }
621         
622         /* some ops have multiple files to select */
623         {
624                 PointerRNA itemptr;
625                 int i, numfiles = filelist_numfiles(sfile->files);
626
627                 if(RNA_struct_find_property(op->ptr, "files")) {
628                         for (i=0; i<numfiles; i++) {
629                                 if (filelist_is_selected(sfile->files, i, CHECK_FILES)) {
630                                         struct direntry *file= filelist_file(sfile->files, i);
631                                         RNA_collection_add(op->ptr, "files", &itemptr);
632                                         RNA_string_set(&itemptr, "name", file->relname);
633                                 }
634                         }
635                 }
636                 
637                 if(RNA_struct_find_property(op->ptr, "dirs")) {
638                         for (i=0; i<numfiles; i++) {
639                                 if (filelist_is_selected(sfile->files, i, CHECK_DIRS)) {
640                                         struct direntry *file= filelist_file(sfile->files, i);
641                                         RNA_collection_add(op->ptr, "dirs", &itemptr);
642                                         RNA_string_set(&itemptr, "name", file->relname);
643                                 }
644                         }
645                 }
646
647
648         }
649 }
650
651 void file_operator_to_sfile(SpaceFile *sfile, wmOperator *op)
652 {
653         int change= FALSE;
654         if(RNA_struct_find_property(op->ptr, "filename")) {
655                 RNA_string_get(op->ptr, "filename", sfile->params->file);
656                 change= TRUE;
657         }
658         if(RNA_struct_find_property(op->ptr, "directory")) {
659                 RNA_string_get(op->ptr, "directory", sfile->params->dir);
660                 change= TRUE;
661         }
662         
663         /* If neither of the above are set, split the filepath back */
664         if(RNA_struct_find_property(op->ptr, "filepath")) {
665                 if(change==FALSE) {
666                         char filepath[FILE_MAX];
667                         RNA_string_get(op->ptr, "filepath", filepath);
668                         BLI_split_dirfile(filepath, sfile->params->dir, sfile->params->file);
669                 }
670         }
671         
672         /* XXX, files and dirs updates missing, not really so important though */
673 }
674
675 void file_draw_check_cb(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
676 {
677         SpaceFile *sfile= CTX_wm_space_file(C);
678         wmOperator *op= sfile->op;
679         if(op) { /* fail on reload */
680                 if(op->type->check) {
681                         char filepath[FILE_MAX];
682                         file_sfile_to_operator(op, sfile, filepath);
683                         
684                         /* redraw */
685                         if(op->type->check(C, op)) {
686                                 file_operator_to_sfile(sfile, op);
687         
688                                 /* redraw, else the changed settings wont get updated */
689                                 ED_area_tag_redraw(CTX_wm_area(C));
690                         }
691                 }
692         }
693 }
694
695 int file_draw_check_exists(SpaceFile *sfile)
696 {
697         if(sfile->op) { /* fails on reload */
698                 if(RNA_struct_find_property(sfile->op->ptr, "check_existing")) {
699                         if(RNA_boolean_get(sfile->op->ptr, "check_existing")) {
700                                 char filepath[FILE_MAX];
701                                 BLI_join_dirfile(filepath, sizeof(filepath), sfile->params->dir, sfile->params->file);
702                                 if(BLI_exists(filepath) && !BLI_is_dir(filepath)) {
703                                         return TRUE;
704                                 }
705                         }
706                 }
707         }
708
709         return FALSE;
710 }
711
712 /* sends events now, so things get handled on windowqueue level */
713 int file_exec(bContext *C, wmOperator *exec_op)
714 {
715         SpaceFile *sfile= CTX_wm_space_file(C);
716         char filepath[FILE_MAX];
717         
718         if(sfile->op) {
719                 wmOperator *op= sfile->op;
720         
721                 /* when used as a macro, for doubleclick, 
722                  to prevent closing when doubleclicking on .. item */
723                 if (RNA_boolean_get(exec_op->ptr, "need_active")) {
724                         int i, active=0;
725                         
726                         for (i=0; i<filelist_numfiles(sfile->files); i++) {
727                                 if(filelist_is_selected(sfile->files, i, CHECK_ALL)) {
728                                         active=1;
729                                         break;
730                                 }
731                         }
732                         if (active == 0)
733                                 return OPERATOR_CANCELLED;
734                 }
735                 
736                 sfile->op = NULL;
737
738                 file_sfile_to_operator(op, sfile, filepath);
739
740                 fsmenu_insert_entry(fsmenu_get(), FS_CATEGORY_RECENT, sfile->params->dir,0, 1);
741                 BLI_make_file_string(G.main->name, filepath, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
742                 fsmenu_write_file(fsmenu_get(), filepath);
743                 WM_event_fileselect_event(C, op, EVT_FILESELECT_EXEC);
744
745         }
746                                 
747         return OPERATOR_FINISHED;
748 }
749
750 void FILE_OT_execute(struct wmOperatorType *ot)
751 {
752         /* identifiers */
753         ot->name= "Execute File Window";
754         ot->description= "Execute selected file";
755         ot->idname= "FILE_OT_execute";
756         
757         /* api callbacks */
758         ot->exec= file_exec;
759         ot->poll= file_operator_poll; 
760         
761         RNA_def_boolean(ot->srna, "need_active", 0, "Need Active", "Only execute if there's an active selected file in the file list.");
762 }
763
764
765 int file_parent_exec(bContext *C, wmOperator *UNUSED(unused))
766 {
767         SpaceFile *sfile= CTX_wm_space_file(C);
768         
769         if(sfile->params) {
770                 if (BLI_has_parent(sfile->params->dir)) {
771                         BLI_parent_dir(sfile->params->dir);
772                         BLI_cleanup_dir(G.main->name, sfile->params->dir);
773                         file_change_dir(C, 0);
774                         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
775                 }
776         }               
777         
778         return OPERATOR_FINISHED;
779
780 }
781
782
783 void FILE_OT_parent(struct wmOperatorType *ot)
784 {
785         /* identifiers */
786         ot->name= "Parent File";
787         ot->description= "Move to parent directory";
788         ot->idname= "FILE_OT_parent";
789         
790         /* api callbacks */
791         ot->exec= file_parent_exec;
792         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
793 }
794
795
796 static int file_refresh_exec(bContext *C, wmOperator *UNUSED(unused))
797 {
798         SpaceFile *sfile= CTX_wm_space_file(C);
799
800         ED_fileselect_clear(C, sfile);
801
802         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
803
804         return OPERATOR_FINISHED;
805
806 }
807
808 void FILE_OT_previous(struct wmOperatorType *ot)
809 {
810         /* identifiers */
811         ot->name= "Previous Folder";
812         ot->description= "Move to previous folder";
813         ot->idname= "FILE_OT_previous";
814         
815         /* api callbacks */
816         ot->exec= file_previous_exec;
817         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
818 }
819
820 int file_previous_exec(bContext *C, wmOperator *UNUSED(unused))
821 {
822         SpaceFile *sfile= CTX_wm_space_file(C);
823
824         if(sfile->params) {
825                 if (!sfile->folders_next)
826                         sfile->folders_next = folderlist_new();
827
828                 folderlist_pushdir(sfile->folders_next, sfile->params->dir);
829                 folderlist_popdir(sfile->folders_prev, sfile->params->dir);
830                 folderlist_pushdir(sfile->folders_next, sfile->params->dir);
831
832                 file_change_dir(C, 1);
833         }
834         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
835
836         return OPERATOR_FINISHED;
837 }
838
839 void FILE_OT_next(struct wmOperatorType *ot)
840 {
841         /* identifiers */
842         ot->name= "Next Folder";
843         ot->description= "Move to next folder";
844         ot->idname= "FILE_OT_next";
845         
846         /* api callbacks */
847         ot->exec= file_next_exec;
848         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
849 }
850
851 int file_next_exec(bContext *C, wmOperator *UNUSED(unused))
852 {
853         SpaceFile *sfile= CTX_wm_space_file(C);
854         if(sfile->params) {
855                 if (!sfile->folders_next)
856                         sfile->folders_next = folderlist_new();
857
858                 folderlist_pushdir(sfile->folders_prev, sfile->params->dir);
859                 folderlist_popdir(sfile->folders_next, sfile->params->dir);
860
861                 // update folders_prev so we can check for it in folderlist_clear_next()
862                 folderlist_pushdir(sfile->folders_prev, sfile->params->dir);
863
864                 file_change_dir(C, 1);
865         }               
866         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
867
868         return OPERATOR_FINISHED;
869 }
870
871
872 /* only meant for timer usage */
873 static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
874 {
875         ScrArea *sa = CTX_wm_area(C);
876         SpaceFile *sfile= CTX_wm_space_file(C);
877         ARegion *ar, *oldar= CTX_wm_region(C);
878         int offset;
879         int numfiles, numfiles_layout;
880         int edit_idx = 0;
881         int i;
882
883         /* escape if not our timer */
884         if(sfile->smoothscroll_timer==NULL || sfile->smoothscroll_timer!=event->customdata)
885                 return OPERATOR_PASS_THROUGH;
886         
887         numfiles = filelist_numfiles(sfile->files);
888
889         /* check if we are editing a name */
890         for (i=0; i < numfiles; ++i)
891         {
892                 if (filelist_is_selected(sfile->files, i, CHECK_ALL) ) {
893                         edit_idx=i;
894                         break;
895                 }
896         }
897
898         /* if we are not editing, we are done */
899         if (0==edit_idx) {
900                 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), sfile->smoothscroll_timer);
901                 sfile->smoothscroll_timer=NULL;
902                 return OPERATOR_PASS_THROUGH;
903         }
904
905         /* we need the correct area for scrolling */
906         ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
907         if (!ar || ar->regiontype != RGN_TYPE_WINDOW) {
908                 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), sfile->smoothscroll_timer);
909                 sfile->smoothscroll_timer=NULL;
910                 return OPERATOR_PASS_THROUGH;
911         }
912
913         offset = ED_fileselect_layout_offset(sfile->layout, (int)ar->v2d.cur.xmin, (int)-ar->v2d.cur.ymax);
914         if (offset<0) offset=0;
915
916         /* scroll offset is the first file in the row/column we are editing in */
917         if (sfile->scroll_offset == 0) {
918                 if (sfile->layout->flag & FILE_LAYOUT_HOR) {
919                         sfile->scroll_offset = (edit_idx/sfile->layout->rows)*sfile->layout->rows;
920                         if (sfile->scroll_offset <= offset) sfile->scroll_offset -= sfile->layout->rows;
921                 } else {
922                         sfile->scroll_offset = (edit_idx/sfile->layout->columns)*sfile->layout->columns;
923                         if (sfile->scroll_offset <= offset) sfile->scroll_offset -= sfile->layout->columns;
924                 }
925         }
926         
927         numfiles_layout = ED_fileselect_layout_numfiles(sfile->layout, ar);
928         
929         /* check if we have reached our final scroll position */
930         if ( (sfile->scroll_offset >= offset) && (sfile->scroll_offset < offset + numfiles_layout) ) {
931                 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), sfile->smoothscroll_timer);
932                 sfile->smoothscroll_timer=NULL;
933                 return OPERATOR_FINISHED;
934         }
935
936         /* temporarily set context to the main window region, 
937          * so the scroll operators work */
938         CTX_wm_region_set(C, ar);
939         
940         /* scroll one step in the desired direction */
941         if (sfile->scroll_offset < offset) {
942                 if (sfile->layout->flag & FILE_LAYOUT_HOR) {
943                         WM_operator_name_call(C, "VIEW2D_OT_scroll_left", 0, NULL);
944                 } else {
945                         WM_operator_name_call(C, "VIEW2D_OT_scroll_up", 0, NULL);
946                 }
947                 
948         } else {
949                 if (sfile->layout->flag & FILE_LAYOUT_HOR) {
950                         WM_operator_name_call(C, "VIEW2D_OT_scroll_right", 0, NULL);
951                 } else {
952                         WM_operator_name_call(C, "VIEW2D_OT_scroll_down", 0, NULL);
953                 }
954         }
955         
956         ED_region_tag_redraw(CTX_wm_region(C));
957         
958         /* and restore context */
959         CTX_wm_region_set(C, oldar);
960         
961         return OPERATOR_FINISHED;
962 }
963
964
965 void FILE_OT_smoothscroll(wmOperatorType *ot)
966 {
967         
968         /* identifiers */
969         ot->name= "Smooth Scroll";
970         ot->idname= "FILE_OT_smoothscroll";
971         ot->description="Smooth scroll to make editable file visible.";
972         
973         /* api callbacks */
974         ot->invoke= file_smoothscroll_invoke;
975         
976         ot->poll= ED_operator_file_active;
977 }
978
979
980 /* create a new, non-existing folder name, returns 1 if successful, 0 if name couldn't be created.
981    The actual name is returned in 'name', 'folder' contains the complete path, including the new folder name.
982 */
983 static int new_folder_path(const char* parent, char *folder, char *name)
984 {
985         int i = 1;
986         int len = 0;
987
988         BLI_strncpy(name, "New Folder", FILE_MAXFILE);
989         BLI_join_dirfile(folder, FILE_MAX, parent, name); /* XXX, not real length */
990         /* check whether folder with the name already exists, in this case
991            add number to the name. Check length of generated name to avoid
992            crazy case of huge number of folders each named 'New Folder (x)' */
993         while (BLI_exists(folder) && (len<FILE_MAXFILE)) {
994                 len = BLI_snprintf(name, FILE_MAXFILE, "New Folder(%d)", i);
995                 BLI_join_dirfile(folder, FILE_MAX, parent, name); /* XXX, not real length */
996                 i++;
997         }
998
999         return (len<FILE_MAXFILE);
1000 }
1001
1002 int file_directory_new_exec(bContext *C, wmOperator *op)
1003 {
1004         char name[FILE_MAXFILE];
1005         char path[FILE_MAX];
1006         int generate_name= 1;
1007
1008         SpaceFile *sfile= CTX_wm_space_file(C);
1009         
1010         if(!sfile->params) {
1011                 BKE_report(op->reports,RPT_WARNING, "No parent directory given.");
1012                 return OPERATOR_CANCELLED;
1013         }
1014         
1015         path[0] = '\0';
1016
1017         if(RNA_struct_find_property(op->ptr, "directory")) {
1018                 RNA_string_get(op->ptr, "directory", path);
1019                 if (path[0] != '\0') generate_name= 0;
1020         }
1021
1022         if (generate_name) {
1023                 /* create a new, non-existing folder name */
1024                 if (!new_folder_path(sfile->params->dir, path, name)) {
1025                         BKE_report(op->reports,RPT_ERROR, "Couldn't create new folder name.");
1026                         return OPERATOR_CANCELLED;
1027                 }
1028         }
1029
1030         /* create the file */
1031         BLI_recurdir_fileops(path);
1032
1033         if (!BLI_exists(path)) {
1034                 BKE_report(op->reports,RPT_ERROR, "Couldn't create new folder.");
1035                 return OPERATOR_CANCELLED;
1036         } 
1037
1038         /* now remember file to jump into editing */
1039         BLI_strncpy(sfile->params->renamefile, name, FILE_MAXFILE);
1040
1041         /* set timer to smoothly view newly generated file */
1042         sfile->smoothscroll_timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER1, 1.0/1000.0);        /* max 30 frs/sec */
1043         sfile->scroll_offset=0;
1044
1045         /* reload dir to make sure we're seeing what's in the directory */
1046         ED_fileselect_clear(C, sfile);
1047         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
1048
1049         return OPERATOR_FINISHED;
1050 }
1051
1052
1053 void FILE_OT_directory_new(struct wmOperatorType *ot)
1054 {
1055         /* identifiers */
1056         ot->name= "Create New Directory";
1057         ot->description= "Create a new directory";
1058         ot->idname= "FILE_OT_directory_new";
1059         
1060         /* api callbacks */
1061         ot->invoke= WM_operator_confirm;
1062         ot->exec= file_directory_new_exec;
1063         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
1064
1065         RNA_def_string_dir_path(ot->srna, "directory", "", FILE_MAX, "Directory", "Name of new directory");
1066
1067 }
1068
1069
1070 static void file_expand_directory(bContext *C)
1071 {
1072         SpaceFile *sfile= CTX_wm_space_file(C);
1073         
1074         if(sfile->params) {
1075                 if ( sfile->params->dir[0] == '~' ) {
1076                         char tmpstr[sizeof(sfile->params->dir)-1];
1077                         BLI_strncpy(tmpstr, sfile->params->dir+1, sizeof(tmpstr));
1078                         BLI_join_dirfile(sfile->params->dir, sizeof(sfile->params->dir), BLI_getDefaultDocumentFolder(), tmpstr);
1079                 }
1080
1081 #ifdef WIN32
1082                 if (sfile->params->dir[0] == '\0')
1083                         get_default_root(sfile->params->dir);
1084 #endif
1085         }
1086 }
1087
1088 static int file_directory_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
1089 {
1090         SpaceFile *sfile= CTX_wm_space_file(C);
1091
1092         if(sfile->params) {
1093                 file_expand_directory(C);
1094                 
1095                 if (!BLI_exists(sfile->params->dir)) {
1096                         return WM_operator_confirm_message(C, op, "Create new directory?");
1097                 } 
1098
1099                 return file_directory_exec(C, op);
1100         }
1101
1102         return OPERATOR_CANCELLED;
1103 }
1104
1105
1106
1107 int file_directory_exec(bContext *C, wmOperator *UNUSED(unused))
1108 {
1109         SpaceFile *sfile= CTX_wm_space_file(C);
1110         
1111         if(sfile->params) {
1112                 file_expand_directory(C);
1113
1114                 if (!BLI_exists(sfile->params->dir)) {
1115                         BLI_recurdir_fileops(sfile->params->dir);
1116                 }
1117
1118                 /* special case, user may have pasted a fulepath into the directory */
1119                 if(BLI_exists(sfile->params->dir) && BLI_is_dir(sfile->params->dir) == 0) {
1120                         char path[sizeof(sfile->params->dir)];
1121                         BLI_strncpy(path, sfile->params->dir, sizeof(path));
1122                         BLI_split_dirfile(path, sfile->params->dir, sfile->params->file);
1123                 }
1124
1125                 BLI_cleanup_dir(G.main->name, sfile->params->dir);
1126                 BLI_add_slash(sfile->params->dir);
1127                 file_change_dir(C, 1);
1128
1129                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
1130         }               
1131         
1132
1133         return OPERATOR_FINISHED;
1134 }
1135
1136 int file_filename_exec(bContext *C, wmOperator *UNUSED(unused))
1137 {
1138         SpaceFile *sfile= CTX_wm_space_file(C);
1139         
1140         if(sfile->params) {
1141                 if (file_select_match(sfile, sfile->params->file))
1142                 {
1143                         sfile->params->file[0] = '\0';
1144                         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_PARAMS, NULL);
1145                 }
1146         }               
1147
1148         return OPERATOR_FINISHED;
1149 }
1150
1151 void FILE_OT_directory(struct wmOperatorType *ot)
1152 {
1153         /* identifiers */
1154         ot->name= "Enter Directory Name";
1155         ot->description= "Enter a directory name";
1156         ot->idname= "FILE_OT_directory";
1157         
1158         /* api callbacks */
1159         ot->invoke= file_directory_invoke;
1160         ot->exec= file_directory_exec;
1161         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
1162 }
1163
1164 void FILE_OT_refresh(struct wmOperatorType *ot)
1165 {
1166         /* identifiers */
1167         ot->name= "Refresh Filelist";
1168         ot->description= "Refresh the file list";
1169         ot->idname= "FILE_OT_refresh";
1170         
1171         /* api callbacks */
1172         ot->exec= file_refresh_exec;
1173         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
1174 }
1175
1176 static int file_hidedot_exec(bContext *C, wmOperator *UNUSED(unused))
1177 {
1178         SpaceFile *sfile= CTX_wm_space_file(C);
1179         
1180         if(sfile->params) {
1181                 sfile->params->flag ^= FILE_HIDE_DOT;
1182                 ED_fileselect_clear(C, sfile);
1183                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
1184         }
1185         
1186         return OPERATOR_FINISHED;
1187 }
1188
1189
1190 void FILE_OT_hidedot(struct wmOperatorType *ot)
1191 {
1192         /* identifiers */
1193         ot->name= "Toggle Hide Dot Files";
1194         ot->description= "Toggle hide hidden dot files";
1195         ot->idname= "FILE_OT_hidedot";
1196         
1197         /* api callbacks */
1198         ot->exec= file_hidedot_exec;
1199         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
1200 }
1201
1202 struct ARegion *file_buttons_region(struct ScrArea *sa)
1203 {
1204         ARegion *ar, *arnew;
1205         
1206         for(ar= sa->regionbase.first; ar; ar= ar->next)
1207                 if(ar->regiontype==RGN_TYPE_CHANNELS)
1208                         return ar;
1209
1210         /* add subdiv level; after header */
1211         for(ar= sa->regionbase.first; ar; ar= ar->next)
1212                 if(ar->regiontype==RGN_TYPE_HEADER)
1213                         break;
1214         
1215         /* is error! */
1216         if(ar==NULL) return NULL;
1217         
1218         arnew= MEM_callocN(sizeof(ARegion), "buttons for file panels");
1219         
1220         BLI_insertlinkafter(&sa->regionbase, ar, arnew);
1221         arnew->regiontype= RGN_TYPE_CHANNELS;
1222         arnew->alignment= RGN_ALIGN_LEFT;
1223         
1224         arnew->flag = RGN_FLAG_HIDDEN;
1225         
1226         return arnew;
1227 }
1228
1229 static int file_bookmark_toggle_exec(bContext *C, wmOperator *UNUSED(unused))
1230 {
1231         ScrArea *sa= CTX_wm_area(C);
1232         ARegion *ar= file_buttons_region(sa);
1233         
1234         if(ar)
1235                 ED_region_toggle_hidden(C, ar);
1236
1237         return OPERATOR_FINISHED;
1238 }
1239
1240 void FILE_OT_bookmark_toggle(struct wmOperatorType *ot)
1241 {
1242         /* identifiers */
1243         ot->name= "Toggle Bookmarks";
1244         ot->description= "Toggle bookmarks display";
1245         ot->idname= "FILE_OT_bookmark_toggle";
1246         
1247         /* api callbacks */
1248         ot->exec= file_bookmark_toggle_exec;
1249         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
1250 }
1251
1252
1253 static int file_filenum_exec(bContext *C, wmOperator *op)
1254 {
1255         SpaceFile *sfile= CTX_wm_space_file(C);
1256         ScrArea *sa= CTX_wm_area(C);
1257         
1258         int inc = RNA_int_get(op->ptr, "increment");
1259         if(sfile->params && (inc != 0)) {
1260                 BLI_newname(sfile->params->file, inc);
1261                 ED_area_tag_redraw(sa);
1262                 file_draw_check_cb(C, NULL, NULL);
1263                 // WM_event_add_notifier(C, NC_WINDOW, NULL);
1264         }
1265         
1266         return OPERATOR_FINISHED;
1267
1268 }
1269
1270 void FILE_OT_filenum(struct wmOperatorType *ot)
1271 {
1272         /* identifiers */
1273         ot->name= "Increment Number in Filename";
1274         ot->description= "Increment number in filename";
1275         ot->idname= "FILE_OT_filenum";
1276         
1277         /* api callbacks */
1278         ot->exec= file_filenum_exec;
1279         ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
1280
1281         /* props */
1282         RNA_def_int(ot->srna, "increment", 1, -100, 100, "Increment", "", -100,100);
1283 }
1284
1285 static int file_rename_exec(bContext *C, wmOperator *UNUSED(op))
1286 {
1287         ScrArea *sa= CTX_wm_area(C);
1288         SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
1289         
1290         if(sfile->params) {
1291                 int idx = sfile->params->active_file;
1292                 int numfiles = filelist_numfiles(sfile->files);
1293                 if ( (0<=idx) && (idx<numfiles) ) {
1294                         struct direntry *file= filelist_file(sfile->files, idx);
1295                         filelist_select_file(sfile->files, idx, FILE_SEL_ADD, EDITING_FILE, CHECK_ALL);
1296                         BLI_strncpy(sfile->params->renameedit, file->relname, FILE_MAXFILE);
1297                         sfile->params->renamefile[0]= '\0';
1298                 }
1299                 ED_area_tag_redraw(sa);
1300         }
1301         
1302         return OPERATOR_FINISHED;
1303
1304 }
1305
1306 static int file_rename_poll(bContext *C)
1307 {
1308         int poll = ED_operator_file_active(C);
1309         SpaceFile *sfile= CTX_wm_space_file(C);
1310
1311         if (sfile && sfile->params) {
1312                 if (sfile->params->active_file < 0) { 
1313                         poll= 0;
1314                 } else {
1315                         char dir[FILE_MAX], group[FILE_MAX];    
1316                         if (filelist_islibrary(sfile->files, dir, group)) poll= 0;
1317                 }
1318         }
1319         else
1320                 poll= 0;
1321         return poll;
1322 }
1323
1324 void FILE_OT_rename(struct wmOperatorType *ot)
1325 {
1326         /* identifiers */
1327         ot->name= "Rename File or Directory";
1328         ot->description= "Rename file or file directory";
1329         ot->idname= "FILE_OT_rename";
1330         
1331         /* api callbacks */
1332         ot->exec= file_rename_exec;
1333         ot->poll= file_rename_poll; 
1334
1335 }
1336
1337 static int file_delete_poll(bContext *C)
1338 {
1339         int poll = ED_operator_file_active(C);
1340         SpaceFile *sfile= CTX_wm_space_file(C);
1341         struct direntry* file;
1342
1343         if (sfile && sfile->params) {
1344                 if (sfile->params->active_file < 0) { 
1345                         poll= 0;
1346                 } else {
1347                         char dir[FILE_MAX], group[FILE_MAX];    
1348                         if (filelist_islibrary(sfile->files, dir, group)) poll= 0;
1349                         file = filelist_file(sfile->files, sfile->params->active_file);
1350                         if (file && S_ISDIR(file->type)) poll= 0;
1351                 }
1352         }
1353         else
1354                 poll= 0;
1355                 
1356         return poll;
1357 }
1358
1359 int file_delete_exec(bContext *C, wmOperator *UNUSED(op))
1360 {
1361         char str[FILE_MAX];
1362         SpaceFile *sfile= CTX_wm_space_file(C);
1363         struct direntry* file;
1364         
1365         
1366         file = filelist_file(sfile->files, sfile->params->active_file);
1367         BLI_make_file_string(G.main->name, str, sfile->params->dir, file->relname);
1368         BLI_delete(str, 0, 0);  
1369         ED_fileselect_clear(C, sfile);
1370         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
1371         
1372         return OPERATOR_FINISHED;
1373
1374 }
1375
1376 void FILE_OT_delete(struct wmOperatorType *ot)
1377 {
1378         /* identifiers */
1379         ot->name= "Delete File";
1380         ot->description= "Delete selected file";
1381         ot->idname= "FILE_OT_delete";
1382         
1383         /* api callbacks */
1384         ot->invoke= WM_operator_confirm;
1385         ot->exec= file_delete_exec;
1386         ot->poll= file_delete_poll; /* <- important, handler is on window level */
1387 }
1388
1389
1390 void ED_operatormacros_file(void)
1391 {
1392 //      wmOperatorType *ot;
1393 //      wmOperatorTypeMacro *otmacro;
1394         
1395         /* future macros */
1396 }