2.5
[blender-staging.git] / source / blender / windowmanager / intern / wm_event_system.c
index 1f417860e0c749ca1f30b420ef7431432c1d8d7b..80cef611974e49a4ff63a5ee3d8b6dff13bf2221 100644 (file)
@@ -50,6 +50,7 @@
 #include "BKE_scene.h"
 #include "BKE_utildefines.h"
 
+#include "ED_fileselect.h"
 #include "ED_screen.h"
 #include "ED_space_api.h"
 #include "ED_util.h"
@@ -455,10 +456,36 @@ int WM_operator_call_py(bContext *C, wmOperatorType *ot, PointerRNA *properties,
 
 /* ********************* handlers *************** */
 
-/* not handler itself, is called by UI to move handlers to other queues, so don't close modal ones */
+/* future extra customadata free? */
 static void wm_event_free_handler(wmEventHandler *handler)
 {
+       MEM_freeN(handler);
+}
+
+/* only set context when area/region is part of screen */
+static void wm_handler_op_context(bContext *C, wmEventHandler *handler)
+{
+       bScreen *screen= CTX_wm_screen(C);
        
+       if(screen && handler->op) {
+               ScrArea *sa;
+               
+               for(sa= screen->areabase.first; sa; sa= sa->next)
+                       if(sa==handler->op_area)
+                               break;
+               if(sa==NULL)
+                       printf("internal error: handler (%s) has invalid area\n", handler->op->type->idname);
+               else {
+                       ARegion *ar;
+                       CTX_wm_area_set(C, sa);
+                       for(ar= sa->regionbase.first; ar; ar= ar->next)
+                               if(ar==handler->op_region)
+                                       break;
+                       /* XXX no warning print here, after full-area and back regions are remade */
+                       if(ar)
+                               CTX_wm_region_set(C, ar);
+               }
+       }
 }
 
 /* called on exit or remove area, only here call cancel callback */
@@ -475,8 +502,7 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers)
                                ScrArea *area= CTX_wm_area(C);
                                ARegion *region= CTX_wm_region(C);
                                
-                               CTX_wm_area_set(C, handler->op_area);
-                               CTX_wm_region_set(C, handler->op_region);
+                               wm_handler_op_context(C, handler);
 
                                handler->op->type->cancel(C, handler->op);
 
@@ -500,7 +526,6 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers)
                }
 
                wm_event_free_handler(handler);
-               MEM_freeN(handler);
        }
 }
 
@@ -597,8 +622,7 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
                        ScrArea *area= CTX_wm_area(C);
                        ARegion *region= CTX_wm_region(C);
                        
-                       CTX_wm_area_set(C, handler->op_area);
-                       CTX_wm_region_set(C, handler->op_region);
+                       wm_handler_op_context(C, handler);
                        
                        retval= ot->modal(C, op, event);
 
@@ -641,7 +665,6 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
                        if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
                                BLI_remlink(handlers, handler);
                                wm_event_free_handler(handler);
-                               MEM_freeN(handler);
                                
                                /* prevent silly errors from operator users */
                                //retval &= ~OPERATOR_PASS_THROUGH;
@@ -693,6 +716,87 @@ static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, wmEvent *eve
        return WM_HANDLER_CONTINUE;
 }
 
+/* fileselect handlers are only in the window queue, so it's save to switch screens or area types */
+static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event)
+{
+       SpaceFile *sfile;
+       int action= WM_HANDLER_CONTINUE;
+       
+       if(event->type != EVT_FILESELECT)
+               return action;
+       if(handler->op != (wmOperator *)event->customdata)
+               return action;
+       
+       switch(event->val) {
+               case EVT_FILESELECT_OPEN: 
+               case EVT_FILESELECT_FULL_OPEN: 
+                       {
+                               int filetype= FILE_BLENDER;
+                               char *path= RNA_string_get_alloc(handler->op->ptr, "filename", NULL, 0);
+                                       
+                               if(RNA_struct_find_property(handler->op->ptr, "filetype"))
+                                       filetype= RNA_int_get(handler->op->ptr, "filetype");
+                               
+                               if(event->val==EVT_FILESELECT_OPEN)
+                                       ED_area_newspace(C, handler->op_area, SPACE_FILE);
+                               else
+                                       ED_screen_full_newspace(C, handler->op_area, SPACE_FILE);
+                               
+                               /* settings for filebrowser, sfile is not operator owner but sends events */
+                               sfile= (SpaceFile*)CTX_wm_space_data(C);
+                               sfile->op= handler->op;
+                               
+                               ED_fileselect_set_params(sfile, filetype, handler->op->type->name, path, 0, 0, 0);
+                               MEM_freeN(path);
+                               
+                               action= WM_HANDLER_BREAK;
+                       }
+                       break;
+                       
+               case EVT_FILESELECT_EXEC:
+               case EVT_FILESELECT_CANCEL:
+                       {
+                               /* XXX validate area and region? */
+                               bScreen *screen= CTX_wm_screen(C);
+                               char *path= RNA_string_get_alloc(handler->op->ptr, "filename", NULL, 0);
+                               
+                               if(screen != handler->filescreen)
+                                       ED_screen_full_prevspace(C);
+                               else
+                                       ED_area_prevspace(C);
+                               
+                               /* remlink now, for load file case */
+                               BLI_remlink(handlers, handler);
+                               
+                               if(event->val==EVT_FILESELECT_EXEC) {
+                                       wm_handler_op_context(C, handler);
+                               
+                                       /* a bit weak, might become arg for WM_event_fileselect? */
+                                       if(strncmp(handler->op->type->name, "Save", 4)==0) {
+                                               /* this gives ownership to pupmenu */
+                                               uiPupMenuSaveOver(C, handler->op, path);
+                                       }
+                                       else {
+                                               handler->op->type->exec(C, handler->op);
+                                               WM_operator_free(handler->op);
+                                       }
+                                       
+                                       CTX_wm_area_set(C, NULL);
+                               }
+                               else 
+                                       WM_operator_free(handler->op);
+                               
+                               wm_event_free_handler(handler);
+                               MEM_freeN(path);
+                               
+                               action= WM_HANDLER_BREAK;
+                       }
+                       break;
+       }
+       
+       return action;
+}
+
 static int handler_boundbox_test(wmEventHandler *handler, wmEvent *event)
 {
        if(handler->bbwin) {
@@ -742,6 +846,10 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
                        else if(handler->ui_handle) {
                                action= wm_handler_ui_call(C, handler, event);
                        }
+                       else if(handler->type==WM_HANDLER_FILESELECT) {
+                               /* screen context changes here */
+                               action= wm_handler_fileselect_call(C, handlers, handler, event);
+                       }
                        else {
                                /* modal, swallows all */
                                action= wm_handler_operator_call(C, handlers, handler, event, NULL);
@@ -930,6 +1038,49 @@ void wm_event_do_handlers(bContext *C)
        }
 }
 
+/* ********** filesector handling ************ */
+
+void WM_event_fileselect_event(bContext *C, void *ophandle, int eventval)
+{
+       /* add to all windows! */
+       wmWindow *win;
+       
+       for(win= CTX_wm_manager(C)->windows.first; win; win= win->next) {
+               wmEvent event= *win->eventstate;
+               
+               event.type= EVT_FILESELECT;
+               event.val= eventval;
+               event.customdata= ophandle;             // only as void pointer type check
+
+               wm_event_add(win, &event);
+       }
+}
+
+/* operator is supposed to have a filled "filename" property */
+/* optional property: filetype (XXX enum?) */
+
+/* Idea is to keep a handler alive on window queue, owning the operator.
+   The filewindow can send event to make it execute, thus ensuring
+   executing happens outside of lower level queues, with UI refreshed. 
+   Should also allow multiwin solutions */
+
+void WM_event_add_fileselect(bContext *C, wmOperator *op)
+{
+       wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "fileselect handler");
+       wmWindow *win= CTX_wm_window(C);
+       int full= 1;    // XXX preset?
+       
+       handler->type= WM_HANDLER_FILESELECT;
+       handler->op= op;
+       handler->op_area= CTX_wm_area(C);
+       handler->op_region= CTX_wm_region(C);
+       handler->filescreen= CTX_wm_screen(C);
+       
+       BLI_addhead(&win->handlers, handler);
+       
+       WM_event_fileselect_event(C, op, full?EVT_FILESELECT_FULL_OPEN:EVT_FILESELECT_OPEN);
+}
+
 /* lets not expose struct outside wm? */
 void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
 {
@@ -997,7 +1148,6 @@ void WM_event_remove_keymap_handler(ListBase *handlers, ListBase *keymap)
                if(handler->keymap==keymap) {
                        BLI_remlink(handlers, handler);
                        wm_event_free_handler(handler);
-                       MEM_freeN(handler);
                        break;
                }
        }
@@ -1025,7 +1175,6 @@ void WM_event_remove_ui_handler(ListBase *handlers, wmUIHandlerFunc func, wmUIHa
                if(handler->ui_handle == func && handler->ui_remove == remove && handler->ui_userdata == userdata) {
                        BLI_remlink(handlers, handler);
                        wm_event_free_handler(handler);
-                       MEM_freeN(handler);
                        break;
                }
        }