svn merge -r 30566:30717 https://svn.blender.org/svnroot/bf-blender/trunk/blender
[blender.git] / source / blender / editors / space_file / file_ops.c
index c515ef6e295c59bc9eb51f9fd9bdae8b78814ba8..2a50b505c57c8e7f6b840ca8a95a10550876e266 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * $Id:
+ * $Id$
  *
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
  * The Original Code is Copyright (C) 2008 Blender Foundation.
  * All rights reserved.
 #include "BKE_context.h"
 #include "BKE_screen.h"
 #include "BKE_global.h"
+#include "BKE_report.h"
 
 #include "BLI_blenlib.h"
 #include "BLI_storage_types.h"
 #ifdef WIN32
 #include "BLI_winstuff.h"
 #endif
-#include "DNA_space_types.h"
-#include "DNA_userdef_types.h"
 
-#include "ED_space_api.h"
 #include "ED_screen.h"
 #include "ED_fileselect.h"
 
@@ -47,7 +45,6 @@
 #include "RNA_access.h"
 #include "RNA_define.h"
 
-#include "UI_interface.h"
 #include "UI_view2d.h"
 
 #include "WM_api.h"
 #include <stdio.h>
 
 /* for events */
-#define NOTACTIVE                      0
+#define NOTACTIVEFILE                  0
 #define ACTIVATE                       1
 #define INACTIVATE                     2
 
 /* ---------- FILE SELECTION ------------ */
 
-static int find_file_mouse(SpaceFile *sfile, struct ARegion* ar, short x, short y, short clamp)
+static int find_file_mouse(SpaceFile *sfile, struct ARegion* ar, int clamp_bounds, int x, int y)
 {
        float fx,fy;
        int active_file = -1;
-       int numfiles = filelist_numfiles(sfile->files);
        View2D* v2d = &ar->v2d;
 
        UI_view2d_region_to_view(v2d, x, y, &fx, &fy);
 
-       active_file = ED_fileselect_layout_offset(sfile->layout, v2d->tot.xmin + fx, v2d->tot.ymax - fy);
-
-       if(active_file < 0) {
-               if(clamp)       active_file=  0;
-               else            active_file= -1;
-       }
-       else if(active_file >= numfiles) {
-               if(clamp)       active_file=  numfiles-1;
-               else            active_file= -1;
-       }
+       active_file = ED_fileselect_layout_offset(sfile->layout, clamp_bounds, v2d->tot.xmin + fx, v2d->tot.ymax - fy);
        
        return active_file;
 }
@@ -99,8 +86,8 @@ static void file_deselect_all(SpaceFile* sfile)
 
        for ( i=0; i < numfiles; ++i) {
                struct direntry* file = filelist_file(sfile->files, i);
-               if (file && (file->flags & ACTIVE)) {
-                       file->flags &= ~ACTIVE;
+               if (file && (file->flags & ACTIVEFILE)) {
+                       file->flags &= ~ACTIVEFILE;
                }
        }
 }
@@ -109,34 +96,85 @@ typedef enum FileSelect { FILE_SELECT_DIR = 1,
   FILE_SELECT_FILE = 2 } FileSelect;
 
 
-static FileSelect file_select(SpaceFile* sfile, ARegion* ar, const rcti* rect, short val)
+static void clamp_to_filelist(int numfiles, int *first_file, int *last_file)
+{
+       /* border select before the first file */
+       if ( (*first_file < 0) && (*last_file >=0 ) ) {
+               *first_file = 0;
+       }
+       /* don't select if everything is outside filelist */
+       if ( (*first_file >= numfiles) && ((*last_file < 0) || (*last_file >= numfiles)) ) {
+               *first_file = -1;
+               *last_file = -1;
+       }
+       
+       /* fix if last file invalid */
+       if ( (*first_file > 0) && (*last_file < 0) )
+               *last_file = numfiles-1;
+
+       /* clamp */
+       if ( (*first_file >= numfiles) ) {
+               *first_file = numfiles-1;
+       }
+       if ( (*last_file >= numfiles) ) {
+               *last_file = numfiles-1;
+       }
+}
+
+static FileSelect file_select(bContext* C, const rcti* rect, short selecting, short toggle_one, short fill)
 {
+       ARegion *ar= CTX_wm_region(C);
+       SpaceFile *sfile= CTX_wm_space_file(C);
        int first_file = -1;
        int last_file = -1;
        int act_file;
-       short selecting = (val == LEFTMOUSE);
        FileSelect retval = FILE_SELECT_FILE;
 
        FileSelectParams *params = ED_fileselect_get_params(sfile);
        // FileLayout *layout = ED_fileselect_get_layout(sfile, ar);
 
        int numfiles = filelist_numfiles(sfile->files);
-
-       params->selstate = NOTACTIVE;
-       first_file = find_file_mouse(sfile, ar, rect->xmin, rect->ymax, 1);
-       last_file = find_file_mouse(sfile, ar, rect->xmax, rect->ymin, 1);
        
+       params->selstate = NOTACTIVEFILE;
+       first_file = find_file_mouse(sfile, ar, 1, rect->xmin, rect->ymax);
+       last_file = find_file_mouse(sfile, ar, 1, rect->xmax, rect->ymin);
+       
+       clamp_to_filelist(numfiles, &first_file, &last_file);
+
+       if (fill && (last_file >= 0) && (last_file < numfiles) ) {
+               int f= last_file;
+               while (f >= 0) {
+                       struct direntry* file = filelist_file(sfile->files, f);
+                       if (file->flags & ACTIVEFILE)
+                               break;
+                       f--;
+               }
+               if (f >= 0) {
+                       first_file = f+1;
+               }
+       }
+
        /* select all valid files between first and last indicated */
        if ( (first_file >= 0) && (first_file < numfiles) && (last_file >= 0) && (last_file < numfiles) ) {
                for (act_file = first_file; act_file <= last_file; act_file++) {
                        struct direntry* file = filelist_file(sfile->files, act_file);
-                       if (selecting) 
-                               file->flags |= ACTIVE;
+                       
+                       if (toggle_one) {
+                               if (file->flags & ACTIVEFILE) {
+                                       file->flags &= ~ACTIVEFILE;
+                                       selecting=0;
+                               } else
+                                       file->flags |= ACTIVEFILE;
+                       } else if (selecting) 
+                               file->flags |= ACTIVEFILE;
                        else
-                               file->flags &= ~ACTIVE;
+                               file->flags &= ~ACTIVEFILE;
                }
        }
 
+       /* Don't act on multiple selected files */
+       if (first_file != last_file) selecting= 0;
+
        /* make the last file active */
        if (selecting && (last_file >= 0 && last_file < numfiles)) {
                struct direntry* file = filelist_file(sfile->files, last_file);
@@ -157,8 +195,7 @@ static FileSelect file_select(SpaceFile* sfile, ARegion* ar, const rcti* rect, s
                                        BLI_add_slash(params->dir);
                                }
 
-                               params->file[0] = '\0';
-                               file_change_dir(sfile);
+                               file_change_dir(C, 0);
                                retval = FILE_SELECT_DIR;
                        }
                }
@@ -169,7 +206,7 @@ static FileSelect file_select(SpaceFile* sfile, ARegion* ar, const rcti* rect, s
                        }
                        
                }       
-       }
+       } 
        return retval;
 }
 
@@ -178,11 +215,10 @@ static FileSelect file_select(SpaceFile* sfile, ARegion* ar, const rcti* rect, s
 static int file_border_select_exec(bContext *C, wmOperator *op)
 {
        ARegion *ar= CTX_wm_region(C);
-       SpaceFile *sfile= CTX_wm_space_file(C);
-       short val;
+       short selecting;
        rcti rect;
-
-       val= RNA_int_get(op->ptr, "event_type");
+       
+       selecting= (RNA_int_get(op->ptr, "gesture_mode")==GESTURE_MODAL_SELECT);
        rect.xmin= RNA_int_get(op->ptr, "xmin");
        rect.ymin= RNA_int_get(op->ptr, "ymin");
        rect.xmax= RNA_int_get(op->ptr, "xmax");
@@ -190,10 +226,10 @@ static int file_border_select_exec(bContext *C, wmOperator *op)
 
        BLI_isect_rcti(&(ar->v2d.mask), &rect, &rect);
        
-       if (FILE_SELECT_DIR == file_select(sfile, ar, &rect, val )) {
-               WM_event_add_notifier(C, NC_FILE|ND_FILELIST, NULL);
+       if (FILE_SELECT_DIR == file_select(C, &rect, selecting, 0, 0)) {
+               WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
        } else {
-               WM_event_add_notifier(C, NC_FILE|ND_PARAMS, NULL);
+               WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_PARAMS, NULL);
        }
        return OPERATOR_FINISHED;
 }
@@ -202,21 +238,17 @@ void FILE_OT_select_border(wmOperatorType *ot)
 {
        /* identifiers */
        ot->name= "Activate/Select File";
+       ot->description= "Activate/select the file(s) contained in the border";
        ot->idname= "FILE_OT_select_border";
        
        /* api callbacks */
        ot->invoke= WM_border_select_invoke;
        ot->exec= file_border_select_exec;
        ot->modal= WM_border_select_modal;
+       ot->poll= ED_operator_file_active;
 
        /* rna */
-       RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
-       RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
-       RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
-       RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
-       RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
-
-       ot->poll= ED_operator_file_active;
+       WM_operator_properties_gesture_border(ot, 0);
 }
 
 static int file_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
@@ -225,6 +257,8 @@ static int file_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
        SpaceFile *sfile= CTX_wm_space_file(C);
        short val;
        rcti rect;
+       int extend = RNA_boolean_get(op->ptr, "extend");
+       int fill = RNA_boolean_get(op->ptr, "fill");
 
        if(ar->regiontype != RGN_TYPE_WINDOW)
                return OPERATOR_CANCELLED;
@@ -237,15 +271,15 @@ static int file_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
                return OPERATOR_CANCELLED;
 
        /* single select, deselect all selected first */
-       file_deselect_all(sfile);
+       if (!extend) file_deselect_all(sfile);
 
-       if (FILE_SELECT_DIR == file_select(sfile, ar, &rect, val ))
-               WM_event_add_notifier(C, NC_FILE|ND_FILELIST, NULL);
+       if (FILE_SELECT_DIR == file_select(C, &rect, 1, extend, fill ))
+               WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
        else
-               WM_event_add_notifier(C, NC_FILE|ND_PARAMS, NULL);
+               WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_PARAMS, NULL);
 
        WM_event_add_mousemove(C); /* for directory changes */
-       WM_event_add_notifier(C, NC_FILE|ND_PARAMS, NULL);
+       WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_PARAMS, NULL);
 
        return OPERATOR_FINISHED;
 }
@@ -254,17 +288,19 @@ void FILE_OT_select(wmOperatorType *ot)
 {
        /* identifiers */
        ot->name= "Activate/Select File";
+       ot->description= "Activate/select file";
        ot->idname= "FILE_OT_select";
        
        /* api callbacks */
        ot->invoke= file_select_invoke;
+       ot->poll= ED_operator_file_active;
 
        /* rna */
-
-       ot->poll= ED_operator_file_active;
+       RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first.");
+       RNA_def_boolean(ot->srna, "fill", 0, "Fill", "Select everything beginning with the last selection.");
 }
 
-static int file_select_all_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int file_select_all_exec(bContext *C, wmOperator *op)
 {
        ScrArea *sa= CTX_wm_area(C);
        SpaceFile *sfile= CTX_wm_space_file(C);
@@ -275,8 +311,8 @@ static int file_select_all_invoke(bContext *C, wmOperator *op, wmEvent *event)
        /* if any file is selected, deselect all first */
        for ( i=0; i < numfiles; ++i) {
                struct direntry* file = filelist_file(sfile->files, i);
-               if (file && (file->flags & ACTIVE)) {
-                       file->flags &= ~ACTIVE;
+               if (file && (file->flags & ACTIVEFILE)) {
+                       file->flags &= ~ACTIVEFILE;
                        select = 0;
                        ED_area_tag_redraw(sa);
                }
@@ -286,7 +322,7 @@ static int file_select_all_invoke(bContext *C, wmOperator *op, wmEvent *event)
                for ( i=0; i < numfiles; ++i) {
                        struct direntry* file = filelist_file(sfile->files, i);
                        if(file && !S_ISDIR(file->type)) {
-                               file->flags |= ACTIVE;
+                               file->flags |= ACTIVEFILE;
                                ED_area_tag_redraw(sa);
                        }
                }
@@ -297,11 +333,12 @@ static int file_select_all_invoke(bContext *C, wmOperator *op, wmEvent *event)
 void FILE_OT_select_all_toggle(wmOperatorType *ot)
 {
        /* identifiers */
-       ot->name= "Select/Deselect all files";
+       ot->name= "Select/Deselect All Files";
+       ot->description= "Select/deselect all files";
        ot->idname= "FILE_OT_select_all_toggle";
        
        /* api callbacks */
-       ot->invoke= file_select_all_invoke;
+       ot->exec= file_select_all_exec;
 
        /* rna */
 
@@ -310,7 +347,7 @@ void FILE_OT_select_all_toggle(wmOperatorType *ot)
 
 /* ---------- BOOKMARKS ----------- */
 
-static int bookmark_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int bookmark_select_exec(bContext *C, wmOperator *op)
 {
        SpaceFile *sfile= CTX_wm_space_file(C);
 
@@ -321,10 +358,9 @@ static int bookmark_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
                RNA_string_get(op->ptr, "dir", entry);
                BLI_strncpy(params->dir, entry, sizeof(params->dir));
                BLI_cleanup_dir(G.sce, params->dir);
-               file_change_dir(sfile);                         
-               params->file[0] = '\0';
+               file_change_dir(C, 1);
 
-               WM_event_add_notifier(C, NC_FILE|ND_FILELIST, NULL);
+               WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
        }
        
        return OPERATOR_FINISHED;
@@ -334,16 +370,17 @@ void FILE_OT_select_bookmark(wmOperatorType *ot)
 {
        /* identifiers */
        ot->name= "Select Directory";
+       ot->description= "Select a bookmarked directory";
        ot->idname= "FILE_OT_select_bookmark";
        
        /* api callbacks */
-       ot->invoke= bookmark_select_invoke;
+       ot->exec= bookmark_select_exec;
        ot->poll= ED_operator_file_active;
 
        RNA_def_string(ot->srna, "dir", "", 256, "Dir", "");
 }
 
-static int bookmark_add_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int bookmark_add_exec(bContext *C, wmOperator *op)
 {
        ScrArea *sa= CTX_wm_area(C);
        SpaceFile *sfile= CTX_wm_space_file(C);
@@ -354,7 +391,7 @@ static int bookmark_add_invoke(bContext *C, wmOperator *op, wmEvent *event)
                char name[FILE_MAX];
        
                fsmenu_insert_entry(fsmenu, FS_CATEGORY_BOOKMARKS, params->dir, 0, 1);
-               BLI_make_file_string("/", name, BLI_gethome(), ".Bfs");
+               BLI_make_file_string("/", name, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
                fsmenu_write_file(fsmenu, name);
        }
 
@@ -362,18 +399,19 @@ static int bookmark_add_invoke(bContext *C, wmOperator *op, wmEvent *event)
        return OPERATOR_FINISHED;
 }
 
-void FILE_OT_add_bookmark(wmOperatorType *ot)
+void FILE_OT_bookmark_add(wmOperatorType *ot)
 {
        /* identifiers */
        ot->name= "Add Bookmark";
-       ot->idname= "FILE_OT_add_bookmark";
+       ot->description= "Add a bookmark for the selected/active directory";
+       ot->idname= "FILE_OT_bookmark_add";
        
        /* api callbacks */
-       ot->invoke= bookmark_add_invoke;
+       ot->exec= bookmark_add_exec;
        ot->poll= ED_operator_file_active;
 }
 
-static int bookmark_delete_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int bookmark_delete_exec(bContext *C, wmOperator *op)
 {
        ScrArea *sa= CTX_wm_area(C);
        struct FSMenu* fsmenu = fsmenu_get();
@@ -385,7 +423,7 @@ static int bookmark_delete_invoke(bContext *C, wmOperator *op, wmEvent *event)
                        char name[FILE_MAX];
                        
                        fsmenu_remove_entry(fsmenu, FS_CATEGORY_BOOKMARKS, index);
-                       BLI_make_file_string("/", name, BLI_gethome(), ".Bfs");
+                       BLI_make_file_string("/", name, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
                        fsmenu_write_file(fsmenu, name);
                        ED_area_tag_redraw(sa);
                }
@@ -398,43 +436,16 @@ void FILE_OT_delete_bookmark(wmOperatorType *ot)
 {
        /* identifiers */
        ot->name= "Delete Bookmark";
+       ot->description= "Delete selected bookmark";
        ot->idname= "FILE_OT_delete_bookmark";
        
        /* api callbacks */
-       ot->invoke= bookmark_delete_invoke;
+       ot->exec= bookmark_delete_exec;
        ot->poll= ED_operator_file_active;
 
        RNA_def_int(ot->srna, "index", -1, -1, 20000, "Index", "", -1, 20000);
 }
 
-
-static int loadimages_invoke(bContext *C, wmOperator *op, wmEvent *event)
-{
-       ScrArea *sa= CTX_wm_area(C);
-       SpaceFile *sfile= CTX_wm_space_file(C);
-       if (sfile->files) {
-               filelist_loadimage_timer(sfile->files);
-               if (filelist_changed(sfile->files)) {
-                       ED_area_tag_redraw(sa);
-               }
-       }
-
-       return OPERATOR_FINISHED;
-}
-
-void FILE_OT_loadimages(wmOperatorType *ot)
-{
-       
-       /* identifiers */
-       ot->name= "Load Images";
-       ot->idname= "FILE_OT_loadimages";
-       
-       /* api callbacks */
-       ot->invoke= loadimages_invoke;
-       
-       ot->poll= ED_operator_file_active;
-}
-
 int file_hilight_set(SpaceFile *sfile, ARegion *ar, int mx, int my)
 {
        FileSelectParams* params;
@@ -451,7 +462,7 @@ int file_hilight_set(SpaceFile *sfile, ARegion *ar, int mx, int my)
        my -= ar->winrct.ymin;
 
        if(BLI_in_rcti(&ar->v2d.mask, mx, my)) {
-               actfile = find_file_mouse(sfile, ar, mx , my, 0);
+               actfile = find_file_mouse(sfile, ar, 0, mx , my);
 
                if((actfile >= 0) && (actfile < numfiles))
                        params->active_file=actfile;
@@ -481,6 +492,7 @@ void FILE_OT_highlight(struct wmOperatorType *ot)
 {
        /* identifiers */
        ot->name= "Highlight File";
+       ot->description= "Highlight selected file(s)";
        ot->idname= "FILE_OT_highlight";
        
        /* api callbacks */
@@ -498,33 +510,80 @@ int file_cancel_exec(bContext *C, wmOperator *unused)
        WM_event_fileselect_event(C, sfile->op, EVT_FILESELECT_CANCEL);
        sfile->op = NULL;
        
+       if (sfile->files) {
+               ED_fileselect_clear(C, sfile);
+               MEM_freeN(sfile->files);
+               sfile->files= NULL;
+       }
+       
        return OPERATOR_FINISHED;
 }
 
+int file_operator_poll(bContext *C)
+{
+       int poll = ED_operator_file_active(C);
+       SpaceFile *sfile= CTX_wm_space_file(C);
+
+       if (!sfile || !sfile->op) poll= 0;
+
+       return poll;
+}
+
 void FILE_OT_cancel(struct wmOperatorType *ot)
 {
        /* identifiers */
        ot->name= "Cancel File Load";
+       ot->description= "Cancel loading of selected file";
        ot->idname= "FILE_OT_cancel";
        
        /* api callbacks */
        ot->exec= file_cancel_exec;
-       ot->poll= ED_operator_file_active;
+       ot->poll= file_operator_poll;
 }
 
 /* sends events now, so things get handled on windowqueue level */
-int file_exec(bContext *C, wmOperator *unused)
+int file_exec(bContext *C, wmOperator *exec_op)
 {
        SpaceFile *sfile= CTX_wm_space_file(C);
-       char name[FILE_MAX];
+       char filepath[FILE_MAX];
        
        if(sfile->op) {
                wmOperator *op= sfile->op;
+       
+               /* when used as a macro, for doubleclick, 
+                to prevent closing when doubleclicking on .. item */
+               if (RNA_boolean_get(exec_op->ptr, "need_active")) {
+                       int i, active=0;
+                       struct direntry *file;
+                       
+                       for (i=0; i<filelist_numfiles(sfile->files); i++) {
+                               file = filelist_file(sfile->files, i);
+                               if(file->flags & ACTIVEFILE) {
+                                       active=1;
+                               }
+                       }
+                       if (active == 0)
+                               return OPERATOR_CANCELLED;
+               }
                
                sfile->op = NULL;
-               BLI_strncpy(name, sfile->params->dir, sizeof(name));
-               strcat(name, sfile->params->file);
-               RNA_string_set(op->ptr, "filename", name);
+
+               BLI_join_dirfile(filepath, sfile->params->dir, sfile->params->file);
+               if(RNA_struct_find_property(op->ptr, "relative_path")) {
+                       if(RNA_boolean_get(op->ptr, "relative_path")) {
+                               BLI_path_rel(filepath, G.sce);
+                       }
+               }
+
+               if(RNA_struct_find_property(op->ptr, "filename")) {
+                       RNA_string_set(op->ptr, "filename", sfile->params->file);
+               }
+               if(RNA_struct_find_property(op->ptr, "directory")) {
+                       RNA_string_set(op->ptr, "directory", sfile->params->dir);
+               }
+               if(RNA_struct_find_property(op->ptr, "filepath")) {
+                       RNA_string_set(op->ptr, "filepath", filepath);
+               }
                
                /* some ops have multiple files to select */
                {
@@ -534,7 +593,7 @@ int file_exec(bContext *C, wmOperator *unused)
                        if(RNA_struct_find_property(op->ptr, "files")) {
                                for (i=0; i<numfiles; i++) {
                                        file = filelist_file(sfile->files, i);
-                                       if(file->flags & ACTIVE) {
+                                       if(file->flags & ACTIVEFILE) {
                                                if ((file->type & S_IFDIR)==0) {
                                                        RNA_collection_add(op->ptr, "files", &itemptr);
                                                        RNA_string_set(&itemptr, "name", file->relname);
@@ -546,7 +605,7 @@ int file_exec(bContext *C, wmOperator *unused)
                        if(RNA_struct_find_property(op->ptr, "dirs")) {
                                for (i=0; i<numfiles; i++) {
                                        file = filelist_file(sfile->files, i);
-                                       if(file->flags & ACTIVE) {
+                                       if(file->flags & ACTIVEFILE) {
                                                if ((file->type & S_IFDIR)) {
                                                        RNA_collection_add(op->ptr, "dirs", &itemptr);
                                                        RNA_string_set(&itemptr, "name", file->relname);
@@ -560,23 +619,30 @@ int file_exec(bContext *C, wmOperator *unused)
                folderlist_free(sfile->folders_next);
 
                fsmenu_insert_entry(fsmenu_get(), FS_CATEGORY_RECENT, sfile->params->dir,0, 1);
-               BLI_make_file_string(G.sce, name, BLI_gethome(), ".Bfs");
-               fsmenu_write_file(fsmenu_get(), name);
+               BLI_make_file_string(G.sce, filepath, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
+               fsmenu_write_file(fsmenu_get(), filepath);
                WM_event_fileselect_event(C, op, EVT_FILESELECT_EXEC);
+
+               ED_fileselect_clear(C, sfile);
+               MEM_freeN(sfile->files);
+               sfile->files= NULL;
        }
                                
        return OPERATOR_FINISHED;
 }
 
-void FILE_OT_exec(struct wmOperatorType *ot)
+void FILE_OT_execute(struct wmOperatorType *ot)
 {
        /* identifiers */
        ot->name= "Execute File Window";
-       ot->idname= "FILE_OT_exec";
+       ot->description= "Execute selected file";
+       ot->idname= "FILE_OT_execute";
        
        /* api callbacks */
        ot->exec= file_exec;
-       ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
+       ot->poll= file_operator_poll; 
+       
+       RNA_def_boolean(ot->srna, "need_active", 0, "Need Active", "Only execute if there's an active selected file in the file list.");
 }
 
 
@@ -588,8 +654,8 @@ int file_parent_exec(bContext *C, wmOperator *unused)
                if (BLI_has_parent(sfile->params->dir)) {
                        BLI_parent_dir(sfile->params->dir);
                        BLI_cleanup_dir(G.sce, sfile->params->dir);
-                       file_change_dir(sfile);
-                       WM_event_add_notifier(C, NC_FILE|ND_FILELIST, NULL);
+                       file_change_dir(C, 0);
+                       WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
                }
        }               
        
@@ -602,6 +668,7 @@ void FILE_OT_parent(struct wmOperatorType *ot)
 {
        /* identifiers */
        ot->name= "Parent File";
+       ot->description= "Move to parent directory";
        ot->idname= "FILE_OT_parent";
        
        /* api callbacks */
@@ -613,10 +680,10 @@ void FILE_OT_parent(struct wmOperatorType *ot)
 int file_refresh_exec(bContext *C, wmOperator *unused)
 {
        SpaceFile *sfile= CTX_wm_space_file(C);
-       
-       file_change_dir(sfile);
 
-       WM_event_add_notifier(C, NC_FILE|ND_FILELIST, NULL);
+       ED_fileselect_clear(C, sfile);
+
+       WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
 
        return OPERATOR_FINISHED;
 
@@ -626,6 +693,7 @@ void FILE_OT_previous(struct wmOperatorType *ot)
 {
        /* identifiers */
        ot->name= "Previous Folder";
+       ot->description= "Move to previous folder";
        ot->idname= "FILE_OT_previous";
        
        /* api callbacks */
@@ -645,9 +713,9 @@ int file_previous_exec(bContext *C, wmOperator *unused)
                folderlist_popdir(sfile->folders_prev, sfile->params->dir);
                folderlist_pushdir(sfile->folders_next, sfile->params->dir);
 
-               file_change_dir(sfile);
+               file_change_dir(C, 1);
        }
-       WM_event_add_notifier(C, NC_FILE|ND_FILELIST, NULL);
+       WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
 
        return OPERATOR_FINISHED;
 }
@@ -656,6 +724,7 @@ void FILE_OT_next(struct wmOperatorType *ot)
 {
        /* identifiers */
        ot->name= "Next Folder";
+       ot->description= "Move to next folder";
        ot->idname= "FILE_OT_next";
        
        /* api callbacks */
@@ -666,8 +735,8 @@ void FILE_OT_next(struct wmOperatorType *ot)
 int file_next_exec(bContext *C, wmOperator *unused)
 {
        SpaceFile *sfile= CTX_wm_space_file(C);
-               if(sfile->params) {
-                       if (!sfile->folders_next)
+       if(sfile->params) {
+               if (!sfile->folders_next)
                        sfile->folders_next = folderlist_new();
 
                folderlist_pushdir(sfile->folders_prev, sfile->params->dir);
@@ -676,38 +745,180 @@ int file_next_exec(bContext *C, wmOperator *unused)
                // update folder_prev so we can check for it in folderlist_clear_next()
                folderlist_pushdir(sfile->folders_prev, sfile->params->dir);
 
-               file_change_dir(sfile);
+               file_change_dir(C, 1);
        }               
-       WM_event_add_notifier(C, NC_FILE|ND_FILELIST, NULL);
+       WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
 
        return OPERATOR_FINISHED;
 }
 
-int file_directory_new_exec(bContext *C, wmOperator *unused)
+
+/* only meant for timer usage */
+static int file_smoothscroll_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+       ScrArea *sa = CTX_wm_area(C);
+       SpaceFile *sfile= CTX_wm_space_file(C);
+       ARegion *ar, *oldar= CTX_wm_region(C);
+       int numfiles, offset;
+       int edit_idx = 0;
+       int numfiles_layout;
+       int i;
+
+       /* escape if not our timer */
+       if(sfile->smoothscroll_timer==NULL || sfile->smoothscroll_timer!=event->customdata)
+               return OPERATOR_PASS_THROUGH;
+       
+       numfiles = filelist_numfiles(sfile->files);
+
+       /* check if we are editing a name */
+       for (i=0; i < numfiles; ++i)
+       {
+               struct direntry *file = filelist_file(sfile->files, i); 
+               if (file->flags & EDITING) {
+                       edit_idx=i;
+                       break;
+               }
+       }
+
+       /* if we are not editing, we are done */
+       if (0==edit_idx) {
+               WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), sfile->smoothscroll_timer);
+               sfile->smoothscroll_timer=NULL;
+               return OPERATOR_PASS_THROUGH;
+       }
+
+       /* we need the correct area for scrolling */
+       ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+       if (!ar || ar->regiontype != RGN_TYPE_WINDOW) {
+               WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), sfile->smoothscroll_timer);
+               sfile->smoothscroll_timer=NULL;
+               return OPERATOR_PASS_THROUGH;
+       }
+
+       offset = ED_fileselect_layout_offset(sfile->layout, 0, ar->v2d.cur.xmin, -ar->v2d.cur.ymax);
+       if (offset<0) offset=0;
+
+       /* scroll offset is the first file in the row/column we are editing in */
+       if (sfile->scroll_offset == 0) {
+               if (sfile->layout->flag & FILE_LAYOUT_HOR) {
+                       sfile->scroll_offset = (edit_idx/sfile->layout->rows)*sfile->layout->rows;
+                       if (sfile->scroll_offset <= offset) sfile->scroll_offset -= sfile->layout->rows;
+               } else {
+                       sfile->scroll_offset = (edit_idx/sfile->layout->columns)*sfile->layout->columns;
+                       if (sfile->scroll_offset <= offset) sfile->scroll_offset -= sfile->layout->columns;
+               }
+       }
+       
+       numfiles_layout = ED_fileselect_layout_numfiles(sfile->layout, ar);
+       
+       /* check if we have reached our final scroll position */
+       if ( (sfile->scroll_offset >= offset) && (sfile->scroll_offset < offset + numfiles_layout) ) {
+               WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), sfile->smoothscroll_timer);
+               sfile->smoothscroll_timer=NULL;
+               return OPERATOR_FINISHED;
+       }
+
+       /* temporarily set context to the main window region, 
+        * so the scroll operators work */
+       CTX_wm_region_set(C, ar);
+       
+       /* scroll one step in the desired direction */
+       if (sfile->scroll_offset < offset) {
+               if (sfile->layout->flag & FILE_LAYOUT_HOR) {
+                       WM_operator_name_call(C, "VIEW2D_OT_scroll_left", 0, NULL);
+               } else {
+                       WM_operator_name_call(C, "VIEW2D_OT_scroll_up", 0, NULL);
+               }
+               
+       } else {
+               if (sfile->layout->flag & FILE_LAYOUT_HOR) {
+                       WM_operator_name_call(C, "VIEW2D_OT_scroll_right", 0, NULL);
+               } else {
+                       WM_operator_name_call(C, "VIEW2D_OT_scroll_down", 0, NULL);
+               }
+       }
+       
+       ED_region_tag_redraw(CTX_wm_region(C));
+       
+       /* and restore context */
+       CTX_wm_region_set(C, oldar);
+       
+       return OPERATOR_FINISHED;
+}
+
+
+void FILE_OT_smoothscroll(wmOperatorType *ot)
+{
+       
+       /* identifiers */
+       ot->name= "Smooth Scroll";
+       ot->idname= "FILE_OT_smoothscroll";
+       ot->description="Smooth scroll to make editable file visible.";
+       
+       /* api callbacks */
+       ot->invoke= file_smoothscroll_invoke;
+       
+       ot->poll= ED_operator_file_active;
+}
+
+
+/* create a new, non-existing folder name, returns 1 if successful, 0 if name couldn't be created.
+   The actual name is returned in 'name', 'folder' contains the complete path, including the new folder name.
+*/
+static int new_folder_path(const char* parent, char *folder, char *name)
 {
-       char tmpstr[FILE_MAX];
-       char tmpdir[FILE_MAXFILE];
        int i = 1;
+       int len = 0;
+
+       BLI_strncpy(name, "New Folder", FILE_MAXFILE);
+       BLI_join_dirfile(folder, parent, name);
+       /* check whether folder with the name already exists, in this case
+          add number to the name. Check length of generated name to avoid
+          crazy case of huge number of folders each named 'New Folder (x)' */
+       while (BLI_exists(folder) && (len<FILE_MAXFILE)) {
+               len = BLI_snprintf(name, FILE_MAXFILE, "New Folder(%d)", i);
+               BLI_join_dirfile(folder, parent, name);
+               i++;
+       }
+
+       return (len<FILE_MAXFILE);
+}
 
+int file_directory_new_exec(bContext *C, wmOperator *op)
+{
+       char name[FILE_MAXFILE];
+       char path[FILE_MAX];
        SpaceFile *sfile= CTX_wm_space_file(C);
        
-       if(sfile->params) {
-                
-               BLI_strncpy(tmpstr, sfile->params->dir, FILE_MAX);
-               BLI_join_dirfile(tmpstr, tmpstr, "New Folder");
-               while (BLI_exists(tmpstr)) {
-                       BLI_snprintf(tmpdir, FILE_MAXFILE, "New Folder(%d)", i++);
-                       BLI_strncpy(tmpstr, sfile->params->dir, FILE_MAX);
-                       BLI_join_dirfile(tmpstr, tmpstr, tmpdir);
-               }
-               BLI_recurdir_fileops(tmpstr);
-               if (!BLI_exists(tmpstr)) {
-                       filelist_free(sfile->files);
-                       filelist_parent(sfile->files);
-                       BLI_strncpy(sfile->params->dir, filelist_dir(sfile->files), FILE_MAX);
-               } 
-       }               
-       WM_event_add_notifier(C, NC_FILE|ND_FILELIST, NULL);
+       if(!sfile->params) {
+               BKE_report(op->reports,RPT_WARNING, "No parent directory given.");
+               return OPERATOR_CANCELLED;
+       }
+       
+       /* create a new, non-existing folder name */
+       if (!new_folder_path(sfile->params->dir, path, name)) {
+               BKE_report(op->reports,RPT_ERROR, "Couldn't create new folder name.");
+               return OPERATOR_CANCELLED;
+       }
+               
+       /* rename the file */
+       BLI_recurdir_fileops(path);
+
+       if (!BLI_exists(path)) {
+               BKE_report(op->reports,RPT_ERROR, "Couldn't create new folder.");
+               return OPERATOR_CANCELLED;
+       } 
+
+       /* now remember file to jump into editing */
+       BLI_strncpy(sfile->params->renamefile, name, FILE_MAXFILE);
+
+       /* set timer to smoothly view newly generated file */
+       sfile->smoothscroll_timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER1, 1.0/1000.0);        /* max 30 frs/sec */
+       sfile->scroll_offset=0;
+
+       /* reload dir to make sure we're seeing what's in the directory */
+       ED_fileselect_clear(C, sfile);
+       WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
 
        return OPERATOR_FINISHED;
 }
@@ -717,6 +928,7 @@ void FILE_OT_directory_new(struct wmOperatorType *ot)
 {
        /* identifiers */
        ot->name= "Create New Directory";
+       ot->description= "Create a new directory";
        ot->idname= "FILE_OT_directory_new";
        
        /* api callbacks */
@@ -727,35 +939,24 @@ void FILE_OT_directory_new(struct wmOperatorType *ot)
 
 int file_directory_exec(bContext *C, wmOperator *unused)
 {
-       char tmpstr[FILE_MAX];
-
        SpaceFile *sfile= CTX_wm_space_file(C);
        
        if(sfile->params) {
-
                if ( sfile->params->dir[0] == '~' ) {
-                       if (sfile->params->dir[1] == '\0') {
-                               BLI_strncpy(sfile->params->dir, BLI_gethome(), sizeof(sfile->params->dir) );
-                       } else {
-                               /* replace ~ with home */
-                               char homestr[FILE_MAX];
-                               char *d = &sfile->params->dir[1];
-
-                               while ( (*d == '\\') || (*d == '/') )
-                                       d++;
-                               BLI_strncpy(homestr,  BLI_gethome(), FILE_MAX);
-                               BLI_join_dirfile(tmpstr, homestr, d);
-                               BLI_strncpy(sfile->params->dir, tmpstr, sizeof(sfile->params->dir));
-                       }
+                       char tmpstr[sizeof(sfile->params->dir)-1];
+                       strncpy(tmpstr, sfile->params->dir+1, sizeof(tmpstr));
+                       BLI_join_dirfile(sfile->params->dir, BLI_getDefaultDocumentFolder(), tmpstr);
                }
+
 #ifdef WIN32
                if (sfile->params->dir[0] == '\0')
                        get_default_root(sfile->params->dir);
 #endif
                BLI_cleanup_dir(G.sce, sfile->params->dir);
                BLI_add_slash(sfile->params->dir);
-               file_change_dir(sfile);
-               WM_event_add_notifier(C, NC_FILE|ND_FILELIST, NULL);
+               file_change_dir(C, 1);
+
+               WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
        }               
        
 
@@ -770,7 +971,7 @@ int file_filename_exec(bContext *C, wmOperator *unused)
                if (file_select_match(sfile, sfile->params->file))
                {
                        sfile->params->file[0] = '\0';
-                       WM_event_add_notifier(C, NC_FILE|ND_PARAMS, NULL);
+                       WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_PARAMS, NULL);
                }
        }               
 
@@ -782,6 +983,7 @@ void FILE_OT_refresh(struct wmOperatorType *ot)
 {
        /* identifiers */
        ot->name= "Refresh Filelist";
+       ot->description= "Refresh the file list";
        ot->idname= "FILE_OT_refresh";
        
        /* api callbacks */
@@ -795,13 +997,11 @@ int file_hidedot_exec(bContext *C, wmOperator *unused)
        
        if(sfile->params) {
                sfile->params->flag ^= FILE_HIDE_DOT;
-               filelist_free(sfile->files);
-               sfile->params->active_file = -1;
-               WM_event_add_notifier(C, NC_FILE|ND_FILELIST, NULL);
+               ED_fileselect_clear(C, sfile);
+               WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
        }
        
        return OPERATOR_FINISHED;
-
 }
 
 
@@ -809,6 +1009,7 @@ void FILE_OT_hidedot(struct wmOperatorType *ot)
 {
        /* identifiers */
        ot->name= "Toggle Hide Dot Files";
+       ot->description= "Toggle hide hidden dot files";
        ot->idname= "FILE_OT_hidedot";
        
        /* api callbacks */
@@ -848,13 +1049,9 @@ int file_bookmark_toggle_exec(bContext *C, wmOperator *unused)
        ScrArea *sa= CTX_wm_area(C);
        ARegion *ar= file_buttons_region(sa);
        
-       if(ar) {
-               ar->flag ^= RGN_FLAG_HIDDEN;
-               ar->v2d.flag &= ~V2D_IS_INITIALISED; /* XXX should become hide/unhide api? */
-               
-               ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa);
-               ED_area_tag_redraw(sa);
-       }
+       if(ar)
+               ED_region_toggle_hidden(C, ar);
+
        return OPERATOR_FINISHED;
 }
 
@@ -862,6 +1059,7 @@ void FILE_OT_bookmark_toggle(struct wmOperatorType *ot)
 {
        /* identifiers */
        ot->name= "Toggle Bookmarks";
+       ot->description= "Toggle bookmarks display";
        ot->idname= "FILE_OT_bookmark_toggle";
        
        /* api callbacks */
@@ -873,11 +1071,13 @@ void FILE_OT_bookmark_toggle(struct wmOperatorType *ot)
 int file_filenum_exec(bContext *C, wmOperator *op)
 {
        SpaceFile *sfile= CTX_wm_space_file(C);
+       ScrArea *sa= CTX_wm_area(C);
        
        int inc = RNA_int_get(op->ptr, "increment");
        if(sfile->params && (inc != 0)) {
                BLI_newname(sfile->params->file, inc);
-               WM_event_add_notifier(C, NC_WINDOW, NULL);
+               ED_area_tag_redraw(sa);
+               // WM_event_add_notifier(C, NC_WINDOW, NULL);
        }
        
        return OPERATOR_FINISHED;
@@ -888,6 +1088,7 @@ void FILE_OT_filenum(struct wmOperatorType *ot)
 {
        /* identifiers */
        ot->name= "Increment Number in Filename";
+       ot->description= "Increment number in filename";
        ot->idname= "FILE_OT_filenum";
        
        /* api callbacks */
@@ -917,15 +1118,34 @@ int file_rename_exec(bContext *C, wmOperator *op)
 
 }
 
+int file_rename_poll(bContext *C)
+{
+       int poll = ED_operator_file_active(C);
+       SpaceFile *sfile= CTX_wm_space_file(C);
+
+       if (sfile && sfile->params) {
+               if (sfile->params->active_file < 0) { 
+                       poll= 0;
+               } else {
+                       char dir[FILE_MAX], group[FILE_MAX];    
+                       if (filelist_islibrary(sfile->files, dir, group)) poll= 0;
+               }
+       }
+       else
+               poll= 0;
+       return poll;
+}
+
 void FILE_OT_rename(struct wmOperatorType *ot)
 {
        /* identifiers */
        ot->name= "Rename File or Directory";
+       ot->description= "Rename file or file directory";
        ot->idname= "FILE_OT_rename";
        
        /* api callbacks */
        ot->exec= file_rename_exec;
-       ot->poll= ED_operator_file_active; /* <- important, handler is on window level */
+       ot->poll= file_rename_poll; 
 
 }
 
@@ -935,10 +1155,12 @@ int file_delete_poll(bContext *C)
        SpaceFile *sfile= CTX_wm_space_file(C);
        struct direntry* file;
 
-       if (sfile->params) {
+       if (sfile && sfile->params) {
                if (sfile->params->active_file < 0) { 
                        poll= 0;
                } else {
+                       char dir[FILE_MAX], group[FILE_MAX];    
+                       if (filelist_islibrary(sfile->files, dir, group)) poll= 0;
                        file = filelist_file(sfile->files, sfile->params->active_file);
                        if (file && S_ISDIR(file->type)) poll= 0;
                }
@@ -959,7 +1181,8 @@ int file_delete_exec(bContext *C, wmOperator *op)
        file = filelist_file(sfile->files, sfile->params->active_file);
        BLI_make_file_string(G.sce, str, sfile->params->dir, file->relname);
        BLI_delete(str, 0, 0);  
-       WM_event_add_notifier(C, NC_FILE | ND_FILELIST, NULL);
+       ED_fileselect_clear(C, sfile);
+       WM_event_add_notifier(C, NC_SPACE|ND_SPACE_FILE_LIST, NULL);
        
        return OPERATOR_FINISHED;
 
@@ -969,6 +1192,7 @@ void FILE_OT_delete(struct wmOperatorType *ot)
 {
        /* identifiers */
        ot->name= "Delete File";
+       ot->description= "Delete selected file";
        ot->idname= "FILE_OT_delete";
        
        /* api callbacks */
@@ -977,3 +1201,15 @@ void FILE_OT_delete(struct wmOperatorType *ot)
        ot->poll= file_delete_poll; /* <- important, handler is on window level */
 }
 
+
+void ED_operatormacros_file(void)
+{
+       wmOperatorType *ot;
+       wmOperatorTypeMacro *otmacro;
+       
+       ot= WM_operatortype_append_macro("FILE_OT_select_execute", "Select and Execute", OPTYPE_UNDO|OPTYPE_REGISTER);
+       WM_operatortype_macro_define(ot, "FILE_OT_select");
+       otmacro= WM_operatortype_macro_define(ot, "FILE_OT_execute");
+       RNA_boolean_set(otmacro->ptr, "need_active", 1);
+
+}