2.5 filebrowser
authorAndrea Weikert <elubie@gmx.net>
Wed, 21 Jan 2009 19:28:28 +0000 (19:28 +0000)
committerAndrea Weikert <elubie@gmx.net>
Wed, 21 Jan 2009 19:28:28 +0000 (19:28 +0000)
cleaned up selection code
new operators:
- highlight file under cursor
- select all/nothing (AKEY)
- border select (BKEY)
changed selection to be invoked by LEFTMOUSE

source/blender/editors/space_file/file_intern.h
source/blender/editors/space_file/file_ops.c
source/blender/editors/space_file/space_file.c
source/blender/windowmanager/intern/wm_operators.c

index 9d52602a1f83cde4d62089889947b5f9f198b950..a551832772b7c3dd3ba73443a97ee81c31cf50de 100644 (file)
@@ -47,7 +47,10 @@ void file_draw_fsmenu(const bContext *C, ARegion *ar);
 
 /* file_ops.h */
 struct wmOperatorType;
+void ED_FILE_OT_highlight(struct wmOperatorType *ot);
 void ED_FILE_OT_select(struct wmOperatorType *ot);
+void ED_FILE_OT_select_all(struct wmOperatorType *ot);
+void ED_FILE_OT_border_select(struct wmOperatorType *ot);
 void ED_FILE_OT_select_bookmark(struct wmOperatorType *ot);
 void ED_FILE_OT_loadimages(struct wmOperatorType *ot);
 
index 2754947b9a533ff0133dc6f69e43d2dc59e3aec7..4c2b7d59368d71bd9c95dc1effc129ceb28d5acb 100644 (file)
 #include "ED_screen.h"
 #include "ED_fileselect.h"
 
-#include "WM_api.h"
-#include "WM_types.h"
+#include "RNA_access.h"
+#include "RNA_define.h"
 
 #include "UI_view2d.h"
 
+#include "WM_api.h"
+#include "WM_types.h"
+
 #include "file_intern.h"
 #include "filelist.h"
 #include "fsmenu.h"
 #define ACTIVATE                       1
 #define INACTIVATE                     2
 
+/* ---------- FILE SELECTION ------------ */
 
-static void set_active_file_thumbs(SpaceFile *sfile, FileSelectParams* params, struct ARegion* ar, short mval[])
+static int find_file_mouse_hor(SpaceFile *sfile, struct ARegion* ar, short x, short y)
 {
-       float x,y;
-       int active_file = -1;
-       struct direntry* file;
+       float fx,fy;
        int offsetx, offsety;
-       int numfiles = filelist_numfiles(sfile->files);
        int columns;
-
+       int active_file = -1;
+       int numfiles = filelist_numfiles(sfile->files);
        View2D* v2d = &ar->v2d;
-       UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
-       
-       offsetx = (x - (v2d->cur.xmin+sfile->tile_border_x))/(sfile->tile_w + 2*sfile->tile_border_x);
-       offsety = (v2d->tot.ymax - sfile->tile_border_y - y)/(sfile->tile_h + 2*sfile->tile_border_y);
+
+       UI_view2d_region_to_view(v2d, x, y, &fx, &fy);
+
+       offsetx = (fx - (v2d->cur.xmin+sfile->tile_border_x))/(sfile->tile_w + 2*sfile->tile_border_x);
+       offsety = (v2d->tot.ymax - sfile->tile_border_y - fy)/(sfile->tile_h + 2*sfile->tile_border_y);
        columns = (v2d->cur.xmax - v2d->cur.xmin) / (sfile->tile_w+ 2*sfile->tile_border_x);
        active_file = offsetx + columns*offsety;
 
-       if (active_file >= 0 && active_file < numfiles )
+       if ( (active_file < 0) || (active_file >= numfiles) )
        {
-               params->active_file = active_file;
-               if (params->selstate & ACTIVATE) {
-                       file = filelist_file(sfile->files, params->active_file);
-                       file->flags |= ACTIVE;
-               }                       
+               active_file = -1;
        }
+       return active_file;
 }
 
 
-static void set_active_file(SpaceFile *sfile, FileSelectParams* params, struct ARegion* ar, short mval[])
+static int find_file_mouse_vert(SpaceFile *sfile, struct ARegion* ar, short x, short y)
 {
        int offsetx, offsety;
-       float x,y;
+       float fx,fy;
        int active_file = -1;
        int numfiles = filelist_numfiles(sfile->files);
        int rows;
-       struct direntry* file;
-
        View2D* v2d = &ar->v2d;
-       UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
+
+       UI_view2d_region_to_view(v2d, x, y, &fx, &fy);
        
-       offsetx = (x-sfile->tile_border_x)/(sfile->tile_w + sfile->tile_border_x);
-       offsety = (v2d->cur.ymax-y-sfile->tile_border_y)/(sfile->tile_h + sfile->tile_border_y);
+       offsetx = (fx-sfile->tile_border_x)/(sfile->tile_w + sfile->tile_border_x);
+       offsety = (v2d->cur.ymax-fy-sfile->tile_border_y)/(sfile->tile_h + sfile->tile_border_y);
        rows = (v2d->cur.ymax - v2d->cur.ymin - 2*sfile->tile_border_y) / (sfile->tile_h+sfile->tile_border_y);
        active_file = rows*offsetx + offsety;
-       if ( (active_file >= 0) && (active_file < numfiles) )
+       if ( (active_file < 0) || (active_file >= numfiles) )
        {
-               params->active_file = active_file;
-               if (params->selstate & ACTIVATE) {
-                       file = filelist_file(sfile->files, params->active_file);
-                       file->flags |= ACTIVE;
-               }                       
-       } 
+               active_file = -1;
+       }
+       return active_file;
 }
 
-
-static void set_active_bookmark(FileSelectParams* params, struct ARegion* ar, short y)
+static void file_deselect_all(SpaceFile* sfile)
 {
-       int nentries = fsmenu_get_nentries();
-       short posy = ar->v2d.mask.ymax - TILE_BORDER_Y - y;
-       params->active_bookmark = ((float)posy / (U.fontsize*3.0f/2.0f));
-       if (params->active_bookmark < 0 || params->active_bookmark > nentries) {
-               params->active_bookmark = -1;
+       int numfiles = filelist_numfiles(sfile->files);
+       int i;
+
+       for ( i=0; i < numfiles; ++i) {
+               struct direntry* file = filelist_file(sfile->files, i);
+               if (file && (file->flags & ACTIVE)) {
+                       file->flags &= ~ACTIVE;
+               }
        }
 }
 
-static void mouse_select(SpaceFile* sfile, FileSelectParams* params, ARegion* ar, short *mval)
+static void file_select(SpaceFile* sfile, FileSelectParams* params, ARegion* ar, const rcti* rect, short val)
 {
+       int first_file = -1;
+       int last_file = -1;
+       int act_file;
+       short selecting = (val == LEFTMOUSE);
+
        int numfiles = filelist_numfiles(sfile->files);
-       if(mval[0]>ar->v2d.mask.xmin && mval[0]<ar->v2d.mask.xmax
-               && mval[1]>ar->v2d.mask.ymin && mval[1]<ar->v2d.mask.ymax) {
-                       params->selstate = NOTACTIVE;
-                       if (params->display) {
-                               set_active_file_thumbs(sfile, params, ar, mval);
+
+       params->selstate = NOTACTIVE;
+       if (params->display) {
+               first_file = find_file_mouse_hor(sfile, ar, rect->xmin, rect->ymax);
+               last_file = find_file_mouse_hor(sfile, ar, rect->xmax, rect->ymin);
+       } else {
+               first_file = find_file_mouse_vert(sfile, ar, rect->xmin, rect->ymax);
+               last_file = find_file_mouse_vert(sfile, ar, rect->xmax, rect->ymin);
+       }
+       
+       /* 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;
+                       else
+                               file->flags &= ~ACTIVE;
+               }
+       }
+       
+       /* make the last file active */
+       if (last_file >= 0 && last_file < numfiles) {
+               struct direntry* file = filelist_file(sfile->files, last_file);
+               params->active_file = last_file;
+
+               if(file && S_ISDIR(file->type)) {
+                       /* the path is too long and we are not going up! */
+                       if (strcmp(file->relname, ".") &&
+                               strcmp(file->relname, "..") &&
+                               strlen(params->dir) + strlen(file->relname) >= FILE_MAX ) 
+                       {
+                               // XXX error("Path too long, cannot enter this directory");
                        } else {
-                               set_active_file(sfile, params, ar, mval);
-                       }
-                       if (params->active_file >= 0 && params->active_file < numfiles) {
-                               struct direntry* file = filelist_file(sfile->files, params->active_file);
-                               
-                               if(file && S_ISDIR(file->type)) {
-                                       /* the path is too long and we are not going up! */
-                                       if (strcmp(file->relname, ".") &&
-                                               strcmp(file->relname, "..") &&
-                                               strlen(params->dir) + strlen(file->relname) >= FILE_MAX ) 
-                                       {
-                                               // XXX error("Path too long, cannot enter this directory");
-                                       } else {
-                                               if (strcmp(file->relname, "..")==0) {
-                                                       /* avoids /../../ */
-                                                       BLI_parent_dir(params->dir);
-                                               } else {
-                                                       strcat(params->dir, file->relname);
-                                                       strcat(params->dir,"/");
-                                                       params->file[0] = '\0';
-                                                       BLI_cleanup_dir(G.sce, params->dir);
-                                               }
-                                               filelist_setdir(sfile->files, params->dir);
-                                               filelist_free(sfile->files);
-                                               params->active_file = -1;
-                                       }
+                               if (strcmp(file->relname, "..")==0) {
+                                       /* avoids /../../ */
+                                       BLI_parent_dir(params->dir);
+                               } else {
+                                       strcat(params->dir, file->relname);
+                                       strcat(params->dir,"/");
+                                       params->file[0] = '\0';
+                                       BLI_cleanup_dir(G.sce, params->dir);
                                }
-                               else if (file)
-                               {
-                                       if (file->relname) {
-                                               BLI_strncpy(params->file, file->relname, FILE_MAXFILE);
-                                               /* XXX
-                                               if(event==MIDDLEMOUSE && filelist_gettype(sfile->files)) 
-                                                       imasel_execute(sfile);
-                                               */
-                                       }
-                                       
-                               }       
+                               filelist_setdir(sfile->files, params->dir);
+                               filelist_free(sfile->files);
+                               params->active_file = -1;
+                       }
+               }
+               else if (file)
+               {
+                       if (file->relname) {
+                               BLI_strncpy(params->file, file->relname, FILE_MAXFILE);
                                /* XXX
-                               if(BIF_filelist_gettype(sfile->files)==FILE_MAIN) {
-                                       active_imasel_object(sfile);
-                               }
+                               if(event==MIDDLEMOUSE && filelist_gettype(sfile->files)) 
+                                       imasel_execute(sfile);
                                */
                        }
+                       
+               }       
+               /* XXX
+               if(BIF_filelist_gettype(sfile->files)==FILE_MAIN) {
+                       active_imasel_object(sfile);
                }
+               */
+       }
+}
+
+
+
+static int file_border_select_exec(bContext *C, wmOperator *op)
+{
+       ARegion *ar= CTX_wm_region(C);
+       SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
+       short val;
+       rcti rect;
+
+       val= RNA_int_get(op->ptr, "event_type");
+       rect.xmin= RNA_int_get(op->ptr, "xmin");
+       rect.ymin= RNA_int_get(op->ptr, "ymin");
+       rect.xmax= RNA_int_get(op->ptr, "xmax");
+       rect.ymax= RNA_int_get(op->ptr, "ymax");
+
+       file_select(sfile, sfile->params, ar, &rect, val );
+       WM_event_add_notifier(C, NC_WINDOW, NULL);
+       return OPERATOR_FINISHED;
 }
 
-static void mouse_select_bookmark(SpaceFile* sfile, ARegion* ar, short *mval)
+void ED_FILE_OT_border_select(wmOperatorType *ot)
 {
-       if(mval[0]>ar->v2d.mask.xmin && mval[0]<ar->v2d.mask.xmax
-       && mval[1]>ar->v2d.mask.ymin && mval[1]<ar->v2d.mask.ymax) {
-               char *selected;
-               set_active_bookmark(sfile->params, ar, mval[1]);
-               selected= fsmenu_get_entry(sfile->params->active_bookmark);                     
-               /* which string */
-               if (selected) {
-                       FileSelectParams* params = sfile->params;
-                       BLI_strncpy(params->dir, selected, sizeof(params->dir));
-                       BLI_cleanup_dir(G.sce, params->dir);
-                       filelist_free(sfile->files);    
-                       filelist_setdir(sfile->files, params->dir);
-                       params->file[0] = '\0';                 
-                       params->active_file = -1;
-               }
-       }
+       /* identifiers */
+       ot->name= "Activate/Select File";
+       ot->idname= "ED_FILE_OT_border_select";
+       
+       /* api callbacks */
+       ot->invoke= WM_border_select_invoke;
+       ot->exec= file_border_select_exec;
+       ot->modal= WM_border_select_modal;
+
+       /* 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;
 }
 
 static int file_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
 {
        ARegion *ar= CTX_wm_region(C);
        SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
-       short mval[2];
-       
-       mval[0]= event->x - ar->winrct.xmin;
-       mval[1]= event->y - ar->winrct.ymin;
-       mouse_select(sfile, sfile->params, ar, mval);
+       short val;
+       rcti rect;
+
+       rect.xmin = rect.xmax = event->x - ar->winrct.xmin;
+       rect.ymin = rect.ymax = event->y - ar->winrct.ymin;
+       val = event->val;
+
+       /* single select, deselect all selected first */
+       file_deselect_all(sfile);
+       file_select(sfile, sfile->params, ar, &rect, val );
        WM_event_add_notifier(C, NC_WINDOW, NULL);
        return OPERATOR_FINISHED;
 }
 
-
 void ED_FILE_OT_select(wmOperatorType *ot)
 {
        /* identifiers */
@@ -224,20 +266,99 @@ void ED_FILE_OT_select(wmOperatorType *ot)
        
        /* api callbacks */
        ot->invoke= file_select_invoke;
+
+       /* rna */
+
        ot->poll= ED_operator_file_active;
 }
 
+static int file_select_all_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+       ScrArea *sa= CTX_wm_area(C);
+       SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
+       int numfiles = filelist_numfiles(sfile->files);
+       int i;
+       int select = 1;
+
+       /* 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;
+                       select = 0;
+                       ED_area_tag_redraw(sa);
+               }
+       }
+       /* select all only if previously no file was selected */
+       if (select) {
+               for ( i=0; i < numfiles; ++i) {
+                       struct direntry* file = filelist_file(sfile->files, i);
+                       if(file && !S_ISDIR(file->type)) {
+                               file->flags |= ACTIVE;
+                               ED_area_tag_redraw(sa);
+                       }
+               }
+       }
+       return OPERATOR_FINISHED;
+}
+
+void ED_FILE_OT_select_all(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Select/Deselect all files";
+       ot->idname= "ED_FILE_OT_select_all";
+       
+       /* api callbacks */
+       ot->invoke= file_select_all_invoke;
+
+       /* rna */
+
+       ot->poll= ED_operator_file_active;
+}
+
+/* ---------- BOOKMARKS ----------- */
+
+static void set_active_bookmark(FileSelectParams* params, struct ARegion* ar, short y)
+{
+       int nentries = fsmenu_get_nentries();
+       short posy = ar->v2d.mask.ymax - TILE_BORDER_Y - y;
+       params->active_bookmark = ((float)posy / (U.fontsize*3.0f/2.0f));
+       if (params->active_bookmark < 0 || params->active_bookmark > nentries) {
+               params->active_bookmark = -1;
+       }
+}
+
+static void file_select_bookmark(SpaceFile* sfile, ARegion* ar, short x, short y)
+{
+       if (BLI_in_rcti(&ar->v2d.mask, x, y)) {
+               char *selected;
+               set_active_bookmark(sfile->params, ar, y);
+               selected= fsmenu_get_entry(sfile->params->active_bookmark);                     
+               /* which string */
+               if (selected) {
+                       FileSelectParams* params = sfile->params;
+                       BLI_strncpy(params->dir, selected, sizeof(params->dir));
+                       BLI_cleanup_dir(G.sce, params->dir);
+                       filelist_free(sfile->files);    
+                       filelist_setdir(sfile->files, params->dir);
+                       params->file[0] = '\0';                 
+                       params->active_file = -1;
+               }
+       }
+}
 
 static int bookmark_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
 {
        ScrArea *sa= CTX_wm_area(C);
-       ARegion *ar= CTX_wm_region(C);
+       ARegion *ar= CTX_wm_region(C);  
        SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
-       short mval[2];
-       
-       mval[0]= event->x - ar->winrct.xmin;
-       mval[1]= event->y - ar->winrct.ymin;
-       mouse_select_bookmark(sfile, ar, mval);
+
+       short x, y;
+
+       x = event->x - ar->winrct.xmin;
+       y = event->y - ar->winrct.ymin;
+
+       file_select_bookmark(sfile, ar, x, y);
        ED_area_tag_redraw(sa);
        return OPERATOR_FINISHED;
 }
@@ -253,11 +374,9 @@ void ED_FILE_OT_select_bookmark(wmOperatorType *ot)
        ot->poll= ED_operator_file_active;
 }
 
-
 static int loadimages_invoke(bContext *C, wmOperator *op, wmEvent *event)
 {
        ScrArea *sa= CTX_wm_area(C);
-       ARegion *ar= CTX_wm_region(C);
        SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
        if (sfile->files) {
                filelist_loadimage_timer(sfile->files);
@@ -266,7 +385,6 @@ static int loadimages_invoke(bContext *C, wmOperator *op, wmEvent *event)
                }
        }
 
-       
        return OPERATOR_FINISHED;
 }
 
@@ -280,5 +398,51 @@ void ED_FILE_OT_loadimages(wmOperatorType *ot)
        /* api callbacks */
        ot->invoke= loadimages_invoke;
        
-       ot->poll= ED_operator_file_active;
-}
\ No newline at end of file
+       ot->poll= ED_operator_areaactive;
+}
+
+
+static int file_highlight_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+       ScrArea *sa= CTX_wm_area(C);
+       ARegion *ar= CTX_wm_region(C);
+       FileSelectParams* params;
+       short x, y;
+       int actfile;
+       int numfiles;
+       SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
+       
+       if (!sfile || !sfile->files) return OPERATOR_FINISHED;
+
+       numfiles = filelist_numfiles(sfile->files);
+
+       x = event->x - ar->winrct.xmin;
+       y = event->y - ar->winrct.ymin;
+
+       params = ED_fileselect_get_params(sfile);
+       if (params->display) {
+               actfile = find_file_mouse_hor(sfile, ar,x , y);
+       } else {
+               actfile = find_file_mouse_vert(sfile, ar, x, y);
+       }
+
+       if (actfile >= 0 && actfile < numfiles )
+       {
+               params->active_file=actfile;
+               ED_area_tag_redraw(sa);
+       }
+       
+       return OPERATOR_FINISHED;
+}
+
+void ED_FILE_OT_highlight(struct wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Highlight File";
+       ot->idname= "ED_FILE_OT_highlight";
+       
+       /* api callbacks */
+       ot->invoke= file_highlight_invoke;
+       ot->poll= ED_operator_areaactive;
+}
+
index b0eb444d62b17368e9a2cf0ddea61d0812b2ca1a..e90436a0c59d954c5fa10605c64892acdae3d482 100644 (file)
@@ -245,18 +245,24 @@ static void file_main_area_draw(const bContext *C, ARegion *ar)
 void file_operatortypes(void)
 {
        WM_operatortype_append(ED_FILE_OT_select);
+       WM_operatortype_append(ED_FILE_OT_select_all);
+       WM_operatortype_append(ED_FILE_OT_border_select);
        WM_operatortype_append(ED_FILE_OT_select_bookmark);
        WM_operatortype_append(ED_FILE_OT_loadimages);
+       WM_operatortype_append(ED_FILE_OT_highlight);
 }
 
 void file_keymap(struct wmWindowManager *wm)
 {
        ListBase *keymap= WM_keymap_listbase(wm, "File", SPACE_FILE, 0);
-       WM_keymap_add_item(keymap, "ED_FILE_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
+       WM_keymap_add_item(keymap, "ED_FILE_OT_select", LEFTMOUSE, KM_PRESS, 0, 0);
+       WM_keymap_add_item(keymap, "ED_FILE_OT_select_all", AKEY, KM_PRESS, 0, 0);
+       WM_keymap_add_item(keymap, "ED_FILE_OT_border_select", BKEY, KM_PRESS, 0, 0);
+       WM_keymap_add_item(keymap, "ED_FILE_OT_highlight", MOUSEMOVE, KM_ANY, 0, 0);
        WM_keymap_add_item(keymap, "ED_FILE_OT_loadimages", TIMER1, KM_ANY, KM_ANY, 0);
 
        keymap= WM_keymap_listbase(wm, "FileBookmark", SPACE_FILE, 0);
-       WM_keymap_add_item(keymap, "ED_FILE_OT_select_bookmark", SELECTMOUSE, KM_PRESS, 0, 0);
+       WM_keymap_add_item(keymap, "ED_FILE_OT_select_bookmark", LEFTMOUSE, KM_PRESS, 0, 0);
 }
 
 
index a895835d3f0c999206068e871fc8cba130f3ead9..1ce6aaf837b3063ca124f3e3556abc7acfa3f161 100644 (file)
@@ -349,7 +349,8 @@ static int wm_mainfile_exec(bContext *C, wmOperator *op)
        
        WM_read_file(C, filename, op->reports);
        
-       WM_event_add_notifier(C, NC_WINDOW, NULL);
+       // XXX wm in context is not set correctly after WM_read_file -> crash
+       // WM_event_add_notifier(C, NC_WINDOW, NULL);
 
        return 0;
 }
@@ -369,6 +370,50 @@ static void WM_OT_open_mainfile(wmOperatorType *ot)
 
 }
 
+static int wm_save_as_mainfile_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+       SpaceFile *sfile;
+       
+       ED_screen_full_newspace(C, CTX_wm_area(C), SPACE_FILE);
+
+       /* settings for filebrowser */
+       sfile= (SpaceFile*)CTX_wm_space_data(C);
+       sfile->op = op;
+       // XXX replace G.sce
+       ED_fileselect_set_params(sfile, FILE_BLENDER, "Save As", G.sce, 0, 0, 0);
+
+       /* screen and area have been reset already in ED_screen_full_newspace */
+
+       return OPERATOR_RUNNING_MODAL;
+}
+
+static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op)
+{
+       char filename[FILE_MAX];
+       RNA_string_get(op->ptr, "filename", filename);
+       
+       WM_write_file(C, filename, op->reports);
+       
+       WM_event_add_notifier(C, NC_WINDOW, NULL);
+
+       return 0;
+}
+
+static void WM_OT_save_as_mainfile(wmOperatorType *ot)
+{
+       ot->name= "Open Blender File";
+       ot->idname= "WM_OT_save_as_mainfile";
+       
+       ot->invoke= wm_save_as_mainfile_invoke;
+       ot->exec= wm_save_as_mainfile_exec;
+       ot->poll= WM_operator_winactive;
+       
+       ot->flag= 0;
+       
+       RNA_def_property(ot->srna, "filename", PROP_STRING, PROP_FILEPATH);
+
+}
+
 /* *********************** */
 
 static void WM_OT_window_fullscreen_toggle(wmOperatorType *ot)
@@ -829,6 +874,7 @@ void wm_operatortype_init(void)
        WM_operatortype_append(WM_OT_tweak_gesture);
        WM_operatortype_append(WM_OT_open_recentfile);
        WM_operatortype_append(WM_OT_open_mainfile);
+       WM_operatortype_append(WM_OT_save_as_mainfile);
 }
 
 /* default keymap for windows and screens, only call once per WM */
@@ -841,6 +887,7 @@ void wm_window_keymap(wmWindowManager *wm)
        WM_keymap_verify_item(keymap, "WM_OT_save_homefile", UKEY, KM_PRESS, KM_CTRL, 0);
        WM_keymap_verify_item(keymap, "WM_OT_open_recentfile", OKEY, KM_PRESS, KM_CTRL, 0);
        WM_keymap_verify_item(keymap, "WM_OT_open_mainfile", F1KEY, KM_PRESS, 0, 0);
+       WM_keymap_verify_item(keymap, "WM_OT_save_as_mainfile", F2KEY, KM_PRESS, 0, 0);
        WM_keymap_verify_item(keymap, "WM_OT_window_fullscreen_toggle", FKEY, KM_PRESS, 0, 0);
        WM_keymap_verify_item(keymap, "WM_OT_exit_blender", QKEY, KM_PRESS, KM_CTRL, 0);
 }