Blender V2.61 - r43446

screen_ops.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version. 
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2008 Blender Foundation.
00019  * All rights reserved.
00020  *
00021  *
00022  * ***** END GPL LICENSE BLOCK *****
00023  */
00024 
00030 #include <math.h>
00031 #include <string.h>
00032 
00033 #include "MEM_guardedalloc.h"
00034 
00035 #include "BLI_math.h"
00036 #include "BLI_blenlib.h"
00037 #include "BLI_editVert.h"
00038 #include "BLI_dlrbTree.h"
00039 #include "BLI_utildefines.h"
00040 
00041 #include "DNA_armature_types.h"
00042 #include "DNA_lattice_types.h"
00043 #include "DNA_object_types.h"
00044 #include "DNA_curve_types.h"
00045 #include "DNA_scene_types.h"
00046 #include "DNA_meta_types.h"
00047 
00048 #include "BKE_context.h"
00049 #include "BKE_customdata.h"
00050 #include "BKE_global.h"
00051 #include "BKE_main.h"
00052 #include "BKE_mesh.h"
00053 #include "BKE_object.h"
00054 #include "BKE_report.h"
00055 #include "BKE_scene.h"
00056 #include "BKE_screen.h"
00057 #include "BKE_sound.h"
00058 
00059 #include "WM_api.h"
00060 #include "WM_types.h"
00061 
00062 #include "ED_util.h"
00063 #include "ED_image.h"
00064 #include "ED_screen.h"
00065 #include "ED_object.h"
00066 #include "ED_armature.h"
00067 #include "ED_screen_types.h"
00068 #include "ED_keyframes_draw.h"
00069 #include "ED_view3d.h"
00070 
00071 #include "RNA_access.h"
00072 #include "RNA_define.h"
00073 
00074 #include "UI_interface.h"
00075 #include "UI_resources.h"
00076 
00077 #include "wm_window.h"
00078 
00079 #include "screen_intern.h"  /* own module include */
00080 
00081 #define KM_MODAL_CANCEL     1
00082 #define KM_MODAL_APPLY      2
00083 #define KM_MODAL_STEP10     3
00084 #define KM_MODAL_STEP10_OFF 4
00085 
00086 /* ************** Exported Poll tests ********************** */
00087 
00088 int ED_operator_regionactive(bContext *C)
00089 {
00090     if(CTX_wm_window(C)==NULL) return 0;
00091     if(CTX_wm_screen(C)==NULL) return 0;
00092     if(CTX_wm_region(C)==NULL) return 0;
00093     return 1;
00094 }
00095 
00096 int ED_operator_areaactive(bContext *C)
00097 {
00098     if(CTX_wm_window(C)==NULL) return 0;
00099     if(CTX_wm_screen(C)==NULL) return 0;
00100     if(CTX_wm_area(C)==NULL) return 0;
00101     return 1;
00102 }
00103 
00104 int ED_operator_screenactive(bContext *C)
00105 {
00106     if(CTX_wm_window(C)==NULL) return 0;
00107     if(CTX_wm_screen(C)==NULL) return 0;
00108     return 1;
00109 }
00110 
00111 /* XXX added this to prevent anim state to change during renders */
00112 static int ED_operator_screenactive_norender(bContext *C)
00113 {
00114     if(G.rendering) return 0;
00115     if(CTX_wm_window(C)==NULL) return 0;
00116     if(CTX_wm_screen(C)==NULL) return 0;
00117     return 1;
00118 }
00119 
00120 
00121 static int screen_active_editable(bContext *C)
00122 {
00123     if(ED_operator_screenactive(C)) {
00124         /* no full window splitting allowed */
00125         if(CTX_wm_screen(C)->full != SCREENNORMAL)
00126             return 0;
00127         return 1;
00128     }
00129     return 0;
00130 }
00131 
00132 /* when mouse is over area-edge */
00133 int ED_operator_screen_mainwinactive(bContext *C)
00134 {
00135     if(CTX_wm_window(C)==NULL) return 0;
00136     if(CTX_wm_screen(C)==NULL) return 0;
00137     if (CTX_wm_screen(C)->subwinactive!=CTX_wm_screen(C)->mainwin) return 0;
00138     return 1;
00139 }
00140 
00141 int ED_operator_scene_editable(bContext *C)
00142 {
00143     Scene *scene= CTX_data_scene(C);
00144     if(scene && scene->id.lib==NULL)
00145         return 1;
00146     return 0;
00147 }
00148 
00149 int ED_operator_objectmode(bContext *C)
00150 {
00151     Scene *scene= CTX_data_scene(C);
00152     Object *obact= CTX_data_active_object(C);
00153 
00154     if(scene==NULL || scene->id.lib)
00155         return 0;
00156     if( CTX_data_edit_object(C) )
00157         return 0;
00158     
00159     /* add a check for ob->mode too? */
00160     if(obact && obact->mode)
00161         return 0;
00162     
00163     return 1;
00164 }
00165 
00166 
00167 static int ed_spacetype_test(bContext *C, int type)
00168 {
00169     if(ED_operator_areaactive(C)) {
00170         SpaceLink *sl= (SpaceLink *)CTX_wm_space_data(C);
00171         return sl && (sl->spacetype == type);
00172     }
00173     return 0;
00174 }
00175 
00176 int ED_operator_view3d_active(bContext *C)
00177 {
00178     return ed_spacetype_test(C, SPACE_VIEW3D);
00179 }
00180 
00181 int ED_operator_region_view3d_active(bContext *C)
00182 {
00183     if(CTX_wm_region_view3d(C))
00184         return TRUE;
00185 
00186     CTX_wm_operator_poll_msg_set(C, "expected a view3d region");
00187     return FALSE;   
00188 }
00189 
00190 /* generic for any view2d which uses anim_ops */
00191 int ED_operator_animview_active(bContext *C)
00192 {
00193     if(ED_operator_areaactive(C)) {
00194         SpaceLink *sl= (SpaceLink *)CTX_wm_space_data(C);
00195         if (sl && (ELEM5(sl->spacetype, SPACE_SEQ, SPACE_ACTION, SPACE_NLA, SPACE_IPO, SPACE_TIME)))
00196             return TRUE;
00197     }
00198 
00199     CTX_wm_operator_poll_msg_set(C, "expected an timeline/animation area to be active");
00200     return 0;
00201 }
00202 
00203 int ED_operator_timeline_active(bContext *C)
00204 {
00205     return ed_spacetype_test(C, SPACE_TIME);
00206 }
00207 
00208 int ED_operator_outliner_active(bContext *C)
00209 {
00210     return ed_spacetype_test(C, SPACE_OUTLINER);
00211 }
00212 
00213 int ED_operator_outliner_active_no_editobject(bContext *C)
00214 {
00215     if(ed_spacetype_test(C, SPACE_OUTLINER)) {
00216         Object *ob = ED_object_active_context(C);
00217         Object *obedit= CTX_data_edit_object(C);
00218         if(ob && ob == obedit)
00219             return 0;
00220         else
00221             return 1;
00222     }
00223     return 0;
00224 }
00225 
00226 int ED_operator_file_active(bContext *C)
00227 {
00228     return ed_spacetype_test(C, SPACE_FILE);
00229 }
00230 
00231 int ED_operator_action_active(bContext *C)
00232 {
00233     return ed_spacetype_test(C, SPACE_ACTION);
00234 }
00235 
00236 int ED_operator_buttons_active(bContext *C)
00237 {
00238     return ed_spacetype_test(C, SPACE_BUTS);
00239 }
00240 
00241 int ED_operator_node_active(bContext *C)
00242 {
00243     SpaceNode *snode= CTX_wm_space_node(C);
00244     
00245     if(snode && snode->edittree)
00246         return 1;
00247     
00248     return 0;
00249 }
00250 
00251 // XXX rename
00252 int ED_operator_graphedit_active(bContext *C)
00253 {
00254     return ed_spacetype_test(C, SPACE_IPO);
00255 }
00256 
00257 int ED_operator_sequencer_active(bContext *C)
00258 {
00259     return ed_spacetype_test(C, SPACE_SEQ);
00260 }
00261 
00262 int ED_operator_image_active(bContext *C)
00263 {
00264     return ed_spacetype_test(C, SPACE_IMAGE);
00265 }
00266 
00267 int ED_operator_nla_active(bContext *C)
00268 {
00269     return ed_spacetype_test(C, SPACE_NLA);
00270 }
00271 
00272 int ED_operator_logic_active(bContext *C)
00273 {
00274     return ed_spacetype_test(C, SPACE_LOGIC);
00275 }
00276 
00277 int ED_operator_info_active(bContext *C)
00278 {
00279     return ed_spacetype_test(C, SPACE_INFO);
00280 }
00281 
00282 
00283 int ED_operator_console_active(bContext *C)
00284 {
00285     return ed_spacetype_test(C, SPACE_CONSOLE);
00286 }
00287 
00288 int ED_operator_object_active(bContext *C)
00289 {
00290     Object *ob = ED_object_active_context(C);
00291     return ((ob != NULL) && !(ob->restrictflag & OB_RESTRICT_VIEW));
00292 }
00293 
00294 int ED_operator_object_active_editable(bContext *C)
00295 {
00296     Object *ob = ED_object_active_context(C);
00297     return ((ob != NULL) && !(ob->id.lib) && !(ob->restrictflag & OB_RESTRICT_VIEW));
00298 }
00299 
00300 int ED_operator_object_active_editable_mesh(bContext *C)
00301 {
00302     Object *ob = ED_object_active_context(C);
00303     return ((ob != NULL) && !(ob->id.lib) && !(ob->restrictflag & OB_RESTRICT_VIEW) && ob->type == OB_MESH && !(((ID *)ob->data)->lib));
00304 }
00305 
00306 int ED_operator_object_active_editable_font(bContext *C)
00307 {
00308     Object *ob = ED_object_active_context(C);
00309     return ((ob != NULL) && !(ob->id.lib) && !(ob->restrictflag & OB_RESTRICT_VIEW) && ob->type == OB_FONT);
00310 }
00311 
00312 int ED_operator_editmesh(bContext *C)
00313 {
00314     Object *obedit= CTX_data_edit_object(C);
00315     if(obedit && obedit->type==OB_MESH)
00316         return NULL != ((Mesh *)obedit->data)->edit_mesh;
00317     return 0;
00318 }
00319 
00320 int ED_operator_editmesh_view3d(bContext *C)
00321 {
00322     return ED_operator_editmesh(C) && ED_operator_view3d_active(C);
00323 }
00324 
00325 int ED_operator_editmesh_region_view3d(bContext *C)
00326 {
00327     if(ED_operator_editmesh(C) && CTX_wm_region_view3d(C))
00328         return 1;
00329 
00330     CTX_wm_operator_poll_msg_set(C, "expected a view3d region & editmesh");
00331     return 0;
00332 }
00333 
00334 int ED_operator_editarmature(bContext *C)
00335 {
00336     Object *obedit= CTX_data_edit_object(C);
00337     if(obedit && obedit->type==OB_ARMATURE)
00338         return NULL != ((bArmature *)obedit->data)->edbo;
00339     return 0;
00340 }
00341 
00342 int ED_operator_posemode(bContext *C)
00343 {
00344     Object *obact= CTX_data_active_object(C);
00345 
00346     if (obact && !(obact->mode & OB_MODE_EDIT)) {
00347         Object *obpose;
00348         if((obpose= object_pose_armature_get(obact))) {
00349             if((obact == obpose) || (obact->mode & OB_MODE_WEIGHT_PAINT)) {
00350                 return 1;
00351             }
00352         }
00353     }
00354 
00355     return 0;
00356 }
00357 
00358 /* wrapper for ED_space_image_show_uvedit */
00359 int ED_operator_uvedit(bContext *C)
00360 {
00361     SpaceImage *sima= CTX_wm_space_image(C);
00362     Object *obedit= CTX_data_edit_object(C);
00363     return ED_space_image_show_uvedit(sima, obedit);
00364 }
00365 
00366 int ED_operator_uvmap(bContext *C)
00367 {
00368     Object *obedit= CTX_data_edit_object(C);
00369     EditMesh *em= NULL;
00370     
00371     if(obedit && obedit->type==OB_MESH)
00372         em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
00373     
00374     if(em && (em->faces.first)) {
00375         BKE_mesh_end_editmesh(obedit->data, em);
00376         return 1;
00377     }
00378     
00379     if(obedit)
00380         BKE_mesh_end_editmesh(obedit->data, em);
00381     return 0;
00382 }
00383 
00384 int ED_operator_editsurfcurve(bContext *C)
00385 {
00386     Object *obedit= CTX_data_edit_object(C);
00387     if(obedit && ELEM(obedit->type, OB_CURVE, OB_SURF))
00388         return NULL != ((Curve *)obedit->data)->editnurb;
00389     return 0;
00390 }
00391 
00392 int ED_operator_editsurfcurve_region_view3d(bContext *C)
00393 {
00394     if(ED_operator_editsurfcurve(C) && CTX_wm_region_view3d(C))
00395         return 1;
00396 
00397     CTX_wm_operator_poll_msg_set(C, "expected a view3d region & editcurve");
00398     return 0;
00399 }
00400 
00401 int ED_operator_editcurve(bContext *C)
00402 {
00403     Object *obedit= CTX_data_edit_object(C);
00404     if(obedit && obedit->type==OB_CURVE)
00405         return NULL != ((Curve *)obedit->data)->editnurb;
00406     return 0;
00407 }
00408 
00409 int ED_operator_editcurve_3d(bContext *C)
00410 {
00411     Object *obedit= CTX_data_edit_object(C);
00412     if(obedit && obedit->type==OB_CURVE) {
00413         Curve *cu= (Curve *)obedit->data;
00414 
00415         return (cu->flag&CU_3D) && (NULL != cu->editnurb);
00416     }
00417     return 0;
00418 }
00419 
00420 int ED_operator_editsurf(bContext *C)
00421 {
00422     Object *obedit= CTX_data_edit_object(C);
00423     if(obedit && obedit->type==OB_SURF)
00424         return NULL != ((Curve *)obedit->data)->editnurb;
00425     return 0;
00426 }
00427 
00428 int ED_operator_editfont(bContext *C)
00429 {
00430     Object *obedit= CTX_data_edit_object(C);
00431     if(obedit && obedit->type==OB_FONT)
00432         return NULL != ((Curve *)obedit->data)->editfont;
00433     return 0;
00434 }
00435 
00436 int ED_operator_editlattice(bContext *C)
00437 {
00438     Object *obedit= CTX_data_edit_object(C);
00439     if(obedit && obedit->type==OB_LATTICE)
00440         return NULL != ((Lattice *)obedit->data)->editlatt;
00441     return 0;
00442 }
00443 
00444 int ED_operator_editmball(bContext *C)
00445 {
00446     Object *obedit= CTX_data_edit_object(C);
00447     if(obedit && obedit->type==OB_MBALL)
00448         return NULL != ((MetaBall *)obedit->data)->editelems;
00449     return 0;
00450 }
00451 
00452 /* *************************** action zone operator ************************** */
00453 
00454 /* operator state vars used:  
00455  none
00456  
00457  functions:
00458  
00459  apply() set actionzone event
00460  
00461  exit() free customdata
00462  
00463  callbacks:
00464  
00465  exec() never used
00466  
00467  invoke() check if in zone  
00468  add customdata, put mouseco and area in it
00469  add modal handler
00470  
00471  modal()    accept modal events while doing it
00472  call apply() with gesture info, active window, nonactive window
00473  call exit() and remove handler when LMB confirm
00474  
00475  */
00476 
00477 typedef struct sActionzoneData {
00478     ScrArea *sa1, *sa2;
00479     AZone *az;
00480     int x, y, gesture_dir, modifier;
00481 } sActionzoneData;
00482 
00483 /* used by other operators too */
00484 static ScrArea *screen_areahascursor(bScreen *scr, int x, int y)
00485 {
00486     ScrArea *sa= NULL;
00487     sa= scr->areabase.first;
00488     while(sa) {
00489         if(BLI_in_rcti(&sa->totrct, x, y)) break;
00490         sa= sa->next;
00491     }
00492     
00493     return sa;
00494 }
00495 
00496 /* quick poll to save operators to be created and handled */
00497 static int actionzone_area_poll(bContext *C)
00498 {
00499     wmWindow *win= CTX_wm_window(C);
00500     ScrArea *sa= CTX_wm_area(C);
00501     
00502     if(sa && win) {
00503         AZone *az;
00504         int x= win->eventstate->x;
00505         int y= win->eventstate->y;
00506         
00507         for(az= sa->actionzones.first; az; az= az->next)
00508             if(BLI_in_rcti(&az->rect, x, y))
00509                 return 1;
00510     }   
00511     return 0;
00512 }
00513 
00514 AZone *is_in_area_actionzone(ScrArea *sa, int x, int y)
00515 {
00516     AZone *az= NULL;
00517     
00518     for(az= sa->actionzones.first; az; az= az->next) {
00519         if(BLI_in_rcti(&az->rect, x, y)) {
00520             if(az->type == AZONE_AREA) {
00521                 /* no triangle intersect but a hotspot circle based on corner */
00522                 int radius= (x-az->x1)*(x-az->x1) + (y-az->y1)*(y-az->y1);
00523                 
00524                 if(radius <= AZONESPOT*AZONESPOT)
00525                     break;
00526             }
00527             else if(az->type == AZONE_REGION) {
00528                 break;
00529             }
00530         }
00531     }
00532     
00533     return az;
00534 }
00535 
00536 
00537 static void actionzone_exit(wmOperator *op)
00538 {
00539     if(op->customdata)
00540         MEM_freeN(op->customdata);
00541     op->customdata= NULL;
00542 }
00543 
00544 /* send EVT_ACTIONZONE event */
00545 static void actionzone_apply(bContext *C, wmOperator *op, int type)
00546 {
00547     wmEvent event;
00548     wmWindow *win= CTX_wm_window(C);
00549     sActionzoneData *sad= op->customdata;
00550     
00551     sad->modifier= RNA_int_get(op->ptr, "modifier");
00552     
00553     event= *(win->eventstate);  /* XXX huh huh? make api call */
00554     if(type==AZONE_AREA)
00555         event.type= EVT_ACTIONZONE_AREA;
00556     else
00557         event.type= EVT_ACTIONZONE_REGION;
00558     event.customdata= op->customdata;
00559     event.customdatafree= TRUE;
00560     op->customdata= NULL;
00561     
00562     wm_event_add(win, &event);
00563 }
00564 
00565 static int actionzone_invoke(bContext *C, wmOperator *op, wmEvent *event)
00566 {
00567     AZone *az= is_in_area_actionzone(CTX_wm_area(C), event->x, event->y);
00568     sActionzoneData *sad;
00569     
00570     /* quick escape */
00571     if(az==NULL)
00572         return OPERATOR_PASS_THROUGH;
00573     
00574     /* ok we do the actionzone */
00575     sad= op->customdata= MEM_callocN(sizeof(sActionzoneData), "sActionzoneData");
00576     sad->sa1= CTX_wm_area(C);
00577     sad->az= az;
00578     sad->x= event->x; sad->y= event->y;
00579     
00580     /* region azone directly reacts on mouse clicks */
00581     if(sad->az->type==AZONE_REGION) {
00582         actionzone_apply(C, op, AZONE_REGION);
00583         actionzone_exit(op);
00584         return OPERATOR_FINISHED;
00585     }
00586     else {
00587         /* add modal handler */
00588         WM_event_add_modal_handler(C, op);
00589         
00590         return OPERATOR_RUNNING_MODAL;
00591     }
00592 }
00593 
00594 
00595 static int actionzone_modal(bContext *C, wmOperator *op, wmEvent *event)
00596 {
00597     sActionzoneData *sad= op->customdata;
00598     int deltax, deltay;
00599     int mindelta= sad->az->type==AZONE_REGION?1:12;
00600     
00601     switch(event->type) {
00602         case MOUSEMOVE:
00603             /* calculate gesture direction */
00604             deltax= (event->x - sad->x);
00605             deltay= (event->y - sad->y);
00606             
00607             if(deltay > ABS(deltax))
00608                 sad->gesture_dir= 'n';
00609             else if(deltax > ABS(deltay))
00610                 sad->gesture_dir= 'e';
00611             else if(deltay < -ABS(deltax))
00612                 sad->gesture_dir= 's';
00613             else
00614                 sad->gesture_dir= 'w';
00615             
00616             /* gesture is large enough? */
00617             if(ABS(deltax) > mindelta || ABS(deltay) > mindelta) {
00618                 
00619                 /* second area, for join */
00620                 sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
00621                 /* apply sends event */
00622                 actionzone_apply(C, op, sad->az->type);
00623                 actionzone_exit(op);
00624                 
00625                 return OPERATOR_FINISHED;
00626             }
00627             break;
00628         case ESCKEY:
00629             actionzone_exit(op);
00630             return OPERATOR_CANCELLED;
00631         case LEFTMOUSE:             
00632             actionzone_exit(op);
00633             return OPERATOR_CANCELLED;
00634             
00635     }
00636     
00637     return OPERATOR_RUNNING_MODAL;
00638 }
00639 
00640 static int actionzone_cancel(bContext *UNUSED(C), wmOperator *op)
00641 {
00642     actionzone_exit(op);
00643 
00644     return OPERATOR_CANCELLED;
00645 }
00646 
00647 static void SCREEN_OT_actionzone(wmOperatorType *ot)
00648 {
00649     /* identifiers */
00650     ot->name= "Handle area action zones";
00651     ot->description= "Handle area action zones for mouse actions/gestures";
00652     ot->idname= "SCREEN_OT_actionzone";
00653     
00654     ot->invoke= actionzone_invoke;
00655     ot->modal= actionzone_modal;
00656     ot->poll= actionzone_area_poll;
00657     ot->cancel= actionzone_cancel;
00658     
00659     ot->flag= OPTYPE_BLOCKING;
00660     
00661     RNA_def_int(ot->srna, "modifier", 0, 0, 2, "Modifier", "Modifier state", 0, 2);
00662 }
00663 
00664 /* ************** swap area operator *********************************** */
00665 
00666 /* operator state vars used:  
00667  sa1        start area
00668  sa2        area to swap with
00669  
00670  functions:
00671  
00672  init()   set custom data for operator, based on actionzone event custom data
00673  
00674  cancel()   cancel the operator
00675  
00676  exit() cleanup, send notifier
00677  
00678  callbacks:
00679  
00680  invoke() gets called on shift+lmb drag in actionzone
00681  call init(), add handler
00682  
00683  modal()  accept modal events while doing it
00684  
00685  */
00686 
00687 typedef struct sAreaSwapData {
00688     ScrArea *sa1, *sa2;
00689 } sAreaSwapData;
00690 
00691 static int area_swap_init(wmOperator *op, wmEvent *event)
00692 {
00693     sAreaSwapData *sd= NULL;
00694     sActionzoneData *sad= event->customdata;
00695     
00696     if(sad==NULL || sad->sa1==NULL)
00697         return 0;
00698     
00699     sd= MEM_callocN(sizeof(sAreaSwapData), "sAreaSwapData");
00700     sd->sa1= sad->sa1;
00701     sd->sa2= sad->sa2;
00702     op->customdata= sd;
00703     
00704     return 1;
00705 }
00706 
00707 
00708 static void area_swap_exit(bContext *C, wmOperator *op)
00709 {
00710     WM_cursor_restore(CTX_wm_window(C));
00711     if(op->customdata)
00712         MEM_freeN(op->customdata);
00713     op->customdata= NULL;
00714 }
00715 
00716 static int area_swap_cancel(bContext *C, wmOperator *op)
00717 {
00718     area_swap_exit(C, op);
00719     return OPERATOR_CANCELLED;
00720 }
00721 
00722 static int area_swap_invoke(bContext *C, wmOperator *op, wmEvent *event)
00723 {
00724     
00725     if(!area_swap_init(op, event))
00726         return OPERATOR_PASS_THROUGH;
00727     
00728     /* add modal handler */
00729     WM_cursor_modal(CTX_wm_window(C), BC_SWAPAREA_CURSOR);
00730     WM_event_add_modal_handler(C, op);
00731     
00732     return OPERATOR_RUNNING_MODAL;
00733     
00734 }
00735 
00736 static int area_swap_modal(bContext *C, wmOperator *op, wmEvent *event)
00737 {
00738     sActionzoneData *sad= op->customdata;
00739     
00740     switch(event->type) {
00741         case MOUSEMOVE:
00742             /* second area, for join */
00743             sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
00744             break;
00745         case LEFTMOUSE: /* release LMB */
00746             if(event->val==KM_RELEASE) {
00747                 if(!sad->sa2 || sad->sa1 == sad->sa2) {
00748                     
00749                     return area_swap_cancel(C, op);
00750                 }
00751 
00752                 ED_area_tag_redraw(sad->sa1);
00753                 ED_area_tag_redraw(sad->sa2);
00754 
00755                 ED_area_swapspace(C, sad->sa1, sad->sa2);
00756                 
00757                 area_swap_exit(C, op);
00758                 
00759                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
00760                 
00761                 return OPERATOR_FINISHED;
00762             }
00763             break;
00764             
00765         case ESCKEY:
00766             return area_swap_cancel(C, op);
00767     }
00768     return OPERATOR_RUNNING_MODAL;
00769 }
00770 
00771 static void SCREEN_OT_area_swap(wmOperatorType *ot)
00772 {
00773     ot->name= "Swap areas";
00774     ot->description= "Swap selected areas screen positions";
00775     ot->idname= "SCREEN_OT_area_swap";
00776     
00777     ot->invoke= area_swap_invoke;
00778     ot->modal= area_swap_modal;
00779     ot->poll= ED_operator_areaactive;
00780     ot->cancel= area_swap_cancel;
00781     
00782     ot->flag= OPTYPE_BLOCKING;
00783 }
00784 
00785 /* *********** Duplicate area as new window operator ****************** */
00786 
00787 /* operator callback */
00788 static int area_dupli_invoke(bContext *C, wmOperator *op, wmEvent *event)
00789 {
00790     wmWindow *newwin, *win;
00791     bScreen *newsc, *sc;
00792     ScrArea *sa;
00793     rcti rect;
00794     
00795     win= CTX_wm_window(C);
00796     sc= CTX_wm_screen(C);
00797     sa= CTX_wm_area(C);
00798     
00799     /* XXX hrmf! */
00800     if(event->type==EVT_ACTIONZONE_AREA) {
00801         sActionzoneData *sad= event->customdata;
00802         
00803         if(sad==NULL)
00804             return OPERATOR_PASS_THROUGH;
00805         
00806         sa= sad->sa1;
00807     }
00808     
00809     /*  poll() checks area context, but we don't accept full-area windows */
00810     if(sc->full != SCREENNORMAL) {
00811         if(event->type==EVT_ACTIONZONE_AREA)
00812             actionzone_exit(op);
00813         return OPERATOR_CANCELLED;
00814     }
00815     
00816     /* adds window to WM */
00817     rect= sa->totrct;
00818     BLI_translate_rcti(&rect, win->posx, win->posy);
00819     newwin= WM_window_open(C, &rect);
00820     
00821     /* allocs new screen and adds to newly created window, using window size */
00822     newsc= ED_screen_add(newwin, CTX_data_scene(C), sc->id.name+2);
00823     newwin->screen= newsc;
00824     
00825     /* copy area to new screen */
00826     area_copy_data((ScrArea *)newsc->areabase.first, sa, 0);
00827 
00828     ED_area_tag_redraw((ScrArea *)newsc->areabase.first);
00829 
00830     /* screen, areas init */
00831     WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
00832     
00833     if(event->type==EVT_ACTIONZONE_AREA)
00834         actionzone_exit(op);
00835     
00836     return OPERATOR_FINISHED;
00837 }
00838 
00839 static void SCREEN_OT_area_dupli(wmOperatorType *ot)
00840 {
00841     ot->name= "Duplicate Area into New Window";
00842     ot->description= "Duplicate selected area into new window";
00843     ot->idname= "SCREEN_OT_area_dupli";
00844     
00845     ot->invoke= area_dupli_invoke;
00846     ot->poll= ED_operator_areaactive;
00847 }
00848 
00849 
00850 /* ************** move area edge operator *********************************** */
00851 
00852 /* operator state vars used:  
00853  x, y               mouse coord near edge
00854  delta            movement of edge
00855  
00856  functions:
00857  
00858  init()   set default property values, find edge based on mouse coords, test
00859  if the edge can be moved, select edges, calculate min and max movement
00860  
00861  apply()    apply delta on selection
00862  
00863  exit() cleanup, send notifier
00864  
00865  cancel() cancel moving
00866  
00867  callbacks:
00868  
00869  exec()   execute without any user interaction, based on properties
00870  call init(), apply(), exit()
00871  
00872  invoke() gets called on mouse click near edge
00873  call init(), add handler
00874  
00875  modal()  accept modal events while doing it
00876  call apply() with delta motion
00877  call exit() and remove handler
00878  
00879  */
00880 
00881 typedef struct sAreaMoveData {
00882     int bigger, smaller, origval, step;
00883     char dir;
00884 } sAreaMoveData;
00885 
00886 /* helper call to move area-edge, sets limits */
00887 static void area_move_set_limits(bScreen *sc, int dir, int *bigger, int *smaller)
00888 {
00889     ScrArea *sa;
00890     int areaminy= ED_area_headersize()+1;
00891     
00892     /* we check all areas and test for free space with MINSIZE */
00893     *bigger= *smaller= 100000;
00894     
00895     for(sa= sc->areabase.first; sa; sa= sa->next) {
00896         if(dir=='h') {
00897             int y1= sa->v2->vec.y - sa->v1->vec.y-areaminy;
00898             
00899             /* if top or down edge selected, test height */
00900             if(sa->v1->flag && sa->v4->flag)
00901                 *bigger= MIN2(*bigger, y1);
00902             else if(sa->v2->flag && sa->v3->flag)
00903                 *smaller= MIN2(*smaller, y1);
00904         }
00905         else {
00906             int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
00907             
00908             /* if left or right edge selected, test width */
00909             if(sa->v1->flag && sa->v2->flag)
00910                 *bigger= MIN2(*bigger, x1);
00911             else if(sa->v3->flag && sa->v4->flag)
00912                 *smaller= MIN2(*smaller, x1);
00913         }
00914     }
00915 }
00916 
00917 /* validate selection inside screen, set variables OK */
00918 /* return 0: init failed */
00919 static int area_move_init (bContext *C, wmOperator *op)
00920 {
00921     bScreen *sc= CTX_wm_screen(C);
00922     ScrEdge *actedge;
00923     sAreaMoveData *md;
00924     int x, y;
00925     
00926     /* required properties */
00927     x= RNA_int_get(op->ptr, "x");
00928     y= RNA_int_get(op->ptr, "y");
00929     
00930     /* setup */
00931     actedge= screen_find_active_scredge(sc, x, y);
00932     if(actedge==NULL) return 0;
00933     
00934     md= MEM_callocN(sizeof(sAreaMoveData), "sAreaMoveData");
00935     op->customdata= md;
00936     
00937     md->dir= scredge_is_horizontal(actedge)?'h':'v';
00938     if(md->dir=='h') md->origval= actedge->v1->vec.y;
00939     else md->origval= actedge->v1->vec.x;
00940     
00941     select_connected_scredge(sc, actedge);
00942     /* now all vertices with 'flag==1' are the ones that can be moved. */
00943     
00944     area_move_set_limits(sc, md->dir, &md->bigger, &md->smaller);
00945     
00946     return 1;
00947 }
00948 
00949 /* moves selected screen edge amount of delta, used by split & move */
00950 static void area_move_apply_do(bContext *C, int origval, int delta, int dir, int bigger, int smaller)
00951 {
00952     wmWindow *win= CTX_wm_window(C);
00953     bScreen *sc= CTX_wm_screen(C);
00954     ScrVert *v1;
00955     ScrArea *sa;
00956     int areaminy= ED_area_headersize()+1;
00957     
00958     delta= CLAMPIS(delta, -smaller, bigger);
00959     
00960     for (v1= sc->vertbase.first; v1; v1= v1->next) {
00961         if (v1->flag) {
00962             /* that way a nice AREAGRID  */
00963             if((dir=='v') && v1->vec.x>0 && v1->vec.x<win->sizex-1) {
00964                 v1->vec.x= origval + delta;
00965                 if(delta != bigger && delta != -smaller) v1->vec.x-= (v1->vec.x % AREAGRID);
00966             }
00967             if((dir=='h') && v1->vec.y>0 && v1->vec.y<win->sizey-1) {
00968                 v1->vec.y= origval + delta;
00969                 
00970                 v1->vec.y+= AREAGRID-1;
00971                 v1->vec.y-= (v1->vec.y % AREAGRID);
00972                 
00973                 /* prevent too small top header */
00974                 if(v1->vec.y > win->sizey-areaminy)
00975                     v1->vec.y= win->sizey-areaminy;
00976             }
00977         }
00978     }
00979 
00980     for(sa= sc->areabase.first; sa; sa= sa->next) {
00981         if(sa->v1->flag || sa->v2->flag || sa->v3->flag || sa->v4->flag)
00982             ED_area_tag_redraw(sa);
00983     }
00984 
00985     WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL); /* redraw everything */
00986 }
00987 
00988 static void area_move_apply(bContext *C, wmOperator *op)
00989 {
00990     sAreaMoveData *md= op->customdata;
00991     int delta;
00992     
00993     delta= RNA_int_get(op->ptr, "delta");
00994     area_move_apply_do(C, md->origval, delta, md->dir, md->bigger, md->smaller);
00995 }
00996 
00997 static void area_move_exit(bContext *C, wmOperator *op)
00998 {
00999     if(op->customdata)
01000         MEM_freeN(op->customdata);
01001     op->customdata= NULL;
01002     
01003     /* this makes sure aligned edges will result in aligned grabbing */
01004     removedouble_scrverts(CTX_wm_screen(C));
01005     removedouble_scredges(CTX_wm_screen(C));
01006 }
01007 
01008 static int area_move_exec(bContext *C, wmOperator *op)
01009 {
01010     if(!area_move_init(C, op))
01011         return OPERATOR_CANCELLED;
01012     
01013     area_move_apply(C, op);
01014     area_move_exit(C, op);
01015     
01016     return OPERATOR_FINISHED;
01017 }
01018 
01019 /* interaction callback */
01020 static int area_move_invoke(bContext *C, wmOperator *op, wmEvent *event)
01021 {
01022     RNA_int_set(op->ptr, "x", event->x);
01023     RNA_int_set(op->ptr, "y", event->y);
01024     
01025     if(!area_move_init(C, op)) 
01026         return OPERATOR_PASS_THROUGH;
01027     
01028     /* add temp handler */
01029     WM_event_add_modal_handler(C, op);
01030     
01031     return OPERATOR_RUNNING_MODAL;
01032 }
01033 
01034 static int area_move_cancel(bContext *C, wmOperator *op)
01035 {
01036     
01037     RNA_int_set(op->ptr, "delta", 0);
01038     area_move_apply(C, op);
01039     area_move_exit(C, op);
01040     
01041     return OPERATOR_CANCELLED;
01042 }
01043 
01044 /* modal callback for while moving edges */
01045 static int area_move_modal(bContext *C, wmOperator *op, wmEvent *event)
01046 {
01047     sAreaMoveData *md= op->customdata;
01048     int delta, x, y;
01049     
01050     /* execute the events */
01051     switch(event->type) {
01052         case MOUSEMOVE:
01053             
01054             x= RNA_int_get(op->ptr, "x");
01055             y= RNA_int_get(op->ptr, "y");
01056             
01057             delta= (md->dir == 'v')? event->x - x: event->y - y;
01058             if(md->step) delta= delta - (delta % md->step);
01059             RNA_int_set(op->ptr, "delta", delta);
01060             
01061             area_move_apply(C, op);
01062             break;
01063             
01064         case EVT_MODAL_MAP:
01065             
01066             switch (event->val) {
01067                 case KM_MODAL_APPLY:
01068                     area_move_exit(C, op);
01069                     return OPERATOR_FINISHED;
01070                     
01071                 case KM_MODAL_CANCEL:
01072                     return area_move_cancel(C, op);
01073                     
01074                 case KM_MODAL_STEP10:
01075                     md->step= 10;
01076                     break;
01077                 case KM_MODAL_STEP10_OFF:
01078                     md->step= 0;
01079                     break;
01080             }
01081     }
01082     
01083     return OPERATOR_RUNNING_MODAL;
01084 }
01085 
01086 static void SCREEN_OT_area_move(wmOperatorType *ot)
01087 {
01088     /* identifiers */
01089     ot->name= "Move area edges";
01090     ot->description= "Move selected area edges";
01091     ot->idname= "SCREEN_OT_area_move";
01092     
01093     ot->exec= area_move_exec;
01094     ot->invoke= area_move_invoke;
01095     ot->cancel= area_move_cancel;
01096     ot->modal= area_move_modal;
01097     ot->poll= ED_operator_screen_mainwinactive; /* when mouse is over area-edge */
01098     
01099     ot->flag= OPTYPE_BLOCKING;
01100     
01101     /* rna */
01102     RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
01103     RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
01104     RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
01105 }
01106 
01107 /* ************** split area operator *********************************** */
01108 
01109 /* 
01110  operator state vars:  
01111  fac              spit point
01112  dir              direction 'v' or 'h'
01113  
01114  operator customdata:
01115  area               pointer to (active) area
01116  x, y           last used mouse pos
01117  (more, see below)
01118  
01119  functions:
01120  
01121  init()   set default property values, find area based on context
01122  
01123  apply()    split area based on state vars
01124  
01125  exit() cleanup, send notifier
01126  
01127  cancel() remove duplicated area
01128  
01129  callbacks:
01130  
01131  exec()   execute without any user interaction, based on state vars
01132  call init(), apply(), exit()
01133  
01134  invoke() gets called on mouse click in action-widget
01135  call init(), add modal handler
01136  call apply() with initial motion
01137  
01138  modal()  accept modal events while doing it
01139  call move-areas code with delta motion
01140  call exit() or cancel() and remove handler
01141  
01142  */
01143 
01144 #define SPLIT_STARTED   1
01145 #define SPLIT_PROGRESS  2
01146 
01147 typedef struct sAreaSplitData {
01148     int x, y;   /* last used mouse position */
01149     
01150     int origval;            /* for move areas */
01151     int bigger, smaller;    /* constraints for moving new edge */
01152     int delta;              /* delta move edge */
01153     int origmin, origsize;  /* to calculate fac, for property storage */
01154     int previewmode;        /* draw previewline, then split */
01155     
01156     ScrEdge *nedge;         /* new edge */
01157     ScrArea *sarea;         /* start area */
01158     ScrArea *narea;         /* new area */
01159     
01160 } sAreaSplitData;
01161 
01162 /* generic init, menu case, doesn't need active area */
01163 static int area_split_menu_init(bContext *C, wmOperator *op)
01164 {
01165     sAreaSplitData *sd;
01166     
01167     /* custom data */
01168     sd= (sAreaSplitData*)MEM_callocN(sizeof (sAreaSplitData), "op_area_split");
01169     op->customdata= sd;
01170     
01171     sd->sarea= CTX_wm_area(C);
01172     
01173     if(sd->sarea) {
01174         int dir= RNA_enum_get(op->ptr, "direction");
01175 
01176         if(dir=='h')
01177             sd->sarea->flag |= AREA_FLAG_DRAWSPLIT_H;
01178         else
01179             sd->sarea->flag |= AREA_FLAG_DRAWSPLIT_V;
01180     }
01181     return 1;
01182 }
01183 
01184 /* generic init, no UI stuff here, assumes active area */
01185 static int area_split_init(bContext *C, wmOperator *op)
01186 {
01187     ScrArea *sa= CTX_wm_area(C);
01188     sAreaSplitData *sd;
01189     int areaminy= ED_area_headersize()+1;
01190     int dir;
01191     
01192     /* required context */
01193     if(sa==NULL) return 0;
01194     
01195     /* required properties */
01196     dir= RNA_enum_get(op->ptr, "direction");
01197     
01198     /* minimal size */
01199     if(dir=='v' && sa->winx < 2*AREAMINX) return 0;
01200     if(dir=='h' && sa->winy < 2*areaminy) return 0;
01201     
01202     /* custom data */
01203     sd= (sAreaSplitData*)MEM_callocN(sizeof (sAreaSplitData), "op_area_split");
01204     op->customdata= sd;
01205     
01206     sd->sarea= sa;
01207     sd->origsize= dir=='v' ? sa->winx:sa->winy;
01208     sd->origmin = dir=='v' ? sa->totrct.xmin:sa->totrct.ymin;
01209     
01210     return 1;
01211 }
01212 
01213 /* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
01214 /* used with split operator */
01215 static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *sa, ScrArea *sb)
01216 {
01217     ScrVert *sav1= sa->v1;
01218     ScrVert *sav2= sa->v2;
01219     ScrVert *sav3= sa->v3;
01220     ScrVert *sav4= sa->v4;
01221     ScrVert *sbv1= sb->v1;
01222     ScrVert *sbv2= sb->v2;
01223     ScrVert *sbv3= sb->v3;
01224     ScrVert *sbv4= sb->v4;
01225     
01226     if(sav1==sbv4 && sav2==sbv3) { /* sa to right of sb = W */
01227         return screen_findedge(screen, sav1, sav2);
01228     }
01229     else if(sav2==sbv1 && sav3==sbv4) { /* sa to bottom of sb = N */
01230         return screen_findedge(screen, sav2, sav3);
01231     }
01232     else if(sav3==sbv2 && sav4==sbv1) { /* sa to left of sb = E */
01233         return screen_findedge(screen, sav3, sav4);
01234     }
01235     else if(sav1==sbv2 && sav4==sbv3) { /* sa on top of sb = S*/
01236         return screen_findedge(screen, sav1, sav4);
01237     }
01238     
01239     return NULL;
01240 }
01241 
01242 
01243 /* do the split, return success */
01244 static int area_split_apply(bContext *C, wmOperator *op)
01245 {
01246     bScreen *sc= CTX_wm_screen(C);
01247     sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
01248     float fac;
01249     int dir;
01250     
01251     fac= RNA_float_get(op->ptr, "factor");
01252     dir= RNA_enum_get(op->ptr, "direction");
01253     
01254     sd->narea= area_split(sc, sd->sarea, dir, fac, 0); /* 0 = no merge */
01255     
01256     if(sd->narea) {
01257         ScrVert *sv;
01258         
01259         sd->nedge= area_findsharededge(sc, sd->sarea, sd->narea);
01260         
01261         /* select newly created edge, prepare for moving edge */
01262         for(sv= sc->vertbase.first; sv; sv= sv->next)
01263             sv->flag = 0;
01264         
01265         sd->nedge->v1->flag= 1;
01266         sd->nedge->v2->flag= 1;
01267         
01268         if(dir=='h') sd->origval= sd->nedge->v1->vec.y;
01269         else sd->origval= sd->nedge->v1->vec.x;
01270 
01271         ED_area_tag_redraw(sd->sarea);
01272         ED_area_tag_redraw(sd->narea);
01273 
01274         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
01275         
01276         return 1;
01277     }       
01278     
01279     return 0;
01280 }
01281 
01282 static void area_split_exit(bContext *C, wmOperator *op)
01283 {
01284     if (op->customdata) {
01285         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
01286         if(sd->sarea) ED_area_tag_redraw(sd->sarea);
01287         if(sd->narea) ED_area_tag_redraw(sd->narea);
01288 
01289         if(sd->sarea)
01290             sd->sarea->flag &= ~(AREA_FLAG_DRAWSPLIT_H|AREA_FLAG_DRAWSPLIT_V);
01291         
01292         MEM_freeN(op->customdata);
01293         op->customdata = NULL;
01294     }
01295     
01296     WM_cursor_restore(CTX_wm_window(C));
01297     WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
01298     
01299     /* this makes sure aligned edges will result in aligned grabbing */
01300     removedouble_scrverts(CTX_wm_screen(C));
01301     removedouble_scredges(CTX_wm_screen(C));
01302 }
01303 
01304 
01305 /* UI callback, adds new handler */
01306 static int area_split_invoke(bContext *C, wmOperator *op, wmEvent *event)
01307 {
01308     sAreaSplitData *sd;
01309     int dir;
01310     
01311     /* no full window splitting allowed */
01312     if(CTX_wm_screen(C)->full != SCREENNORMAL)
01313         return OPERATOR_CANCELLED;
01314     
01315     if(event->type==EVT_ACTIONZONE_AREA) {
01316         sActionzoneData *sad= event->customdata;
01317         
01318         if(sad->modifier>0) {
01319             return OPERATOR_PASS_THROUGH;
01320         }
01321         
01322         /* verify *sad itself */
01323         if(sad==NULL || sad->sa1==NULL || sad->az==NULL)
01324             return OPERATOR_PASS_THROUGH;
01325         
01326         /* is this our *sad? if areas not equal it should be passed on */
01327         if(CTX_wm_area(C)!=sad->sa1 || sad->sa1!=sad->sa2)
01328             return OPERATOR_PASS_THROUGH;
01329         
01330         /* prepare operator state vars */
01331         if(sad->gesture_dir=='n' || sad->gesture_dir=='s') {
01332             dir= 'h';
01333             RNA_float_set(op->ptr, "factor", ((float)(event->x - sad->sa1->v1->vec.x)) / (float)sad->sa1->winx);
01334         }
01335         else {
01336             dir= 'v';
01337             RNA_float_set(op->ptr, "factor", ((float)(event->y - sad->sa1->v1->vec.y)) / (float)sad->sa1->winy);
01338         }
01339         RNA_enum_set(op->ptr, "direction", dir);
01340         
01341         /* general init, also non-UI case, adds customdata, sets area and defaults */
01342         if(!area_split_init(C, op))
01343             return OPERATOR_PASS_THROUGH;
01344         
01345     }
01346     else {
01347         ScrEdge *actedge;
01348         int x, y;
01349         
01350         /* retrieve initial mouse coord, so we can find the active edge */
01351         if(RNA_struct_property_is_set(op->ptr, "mouse_x"))
01352             x= RNA_int_get(op->ptr, "mouse_x");
01353         else
01354             x= event->x;
01355         
01356         if(RNA_struct_property_is_set(op->ptr, "mouse_y"))
01357             y= RNA_int_get(op->ptr, "mouse_y");
01358         else
01359             y= event->x;
01360         
01361         actedge= screen_find_active_scredge(CTX_wm_screen(C), x, y);
01362         if(actedge==NULL) 
01363             return OPERATOR_CANCELLED;
01364         
01365         dir= scredge_is_horizontal(actedge)?'v':'h';
01366         
01367         RNA_enum_set(op->ptr, "direction", dir);
01368         
01369         /* special case, adds customdata, sets defaults */
01370         if(!area_split_menu_init(C, op))
01371             return OPERATOR_CANCELLED;
01372         
01373     }
01374     
01375     sd= (sAreaSplitData *)op->customdata;
01376     
01377     sd->x= event->x;
01378     sd->y= event->y;
01379     
01380     if(event->type==EVT_ACTIONZONE_AREA) {
01381         
01382         /* do the split */
01383         if(area_split_apply(C, op)) {
01384             area_move_set_limits(CTX_wm_screen(C), dir, &sd->bigger, &sd->smaller);
01385             
01386             /* add temp handler for edge move or cancel */
01387             WM_event_add_modal_handler(C, op);
01388             
01389             return OPERATOR_RUNNING_MODAL;
01390         }
01391     }
01392     else {
01393         sd->previewmode= 1;
01394         /* add temp handler for edge move or cancel */
01395         WM_event_add_modal_handler(C, op);
01396         
01397         return OPERATOR_RUNNING_MODAL;
01398         
01399     }
01400     
01401     return OPERATOR_PASS_THROUGH;
01402 }
01403 
01404 /* function to be called outside UI context, or for redo */
01405 static int area_split_exec(bContext *C, wmOperator *op)
01406 {
01407     
01408     if(!area_split_init(C, op))
01409         return OPERATOR_CANCELLED;
01410     
01411     area_split_apply(C, op);
01412     area_split_exit(C, op);
01413     
01414     return OPERATOR_FINISHED;
01415 }
01416 
01417 
01418 static int area_split_cancel(bContext *C, wmOperator *op)
01419 {
01420     sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
01421     
01422     if(sd->previewmode) {
01423     }
01424     else {
01425         if (screen_area_join(C, CTX_wm_screen(C), sd->sarea, sd->narea)) {
01426             if (CTX_wm_area(C) == sd->narea) {
01427                 CTX_wm_area_set(C, NULL);
01428                 CTX_wm_region_set(C, NULL);
01429             }
01430             sd->narea = NULL;
01431         }
01432     }
01433     area_split_exit(C, op);
01434     
01435     return OPERATOR_CANCELLED;
01436 }
01437 
01438 static int area_split_modal(bContext *C, wmOperator *op, wmEvent *event)
01439 {
01440     sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
01441     float fac;
01442     int dir;
01443     
01444     /* execute the events */
01445     switch(event->type) {
01446         case MOUSEMOVE:
01447             dir= RNA_enum_get(op->ptr, "direction");
01448             
01449             sd->delta= (dir == 'v')? event->x - sd->origval: event->y - sd->origval;
01450             if(sd->previewmode==0) 
01451                 area_move_apply_do(C, sd->origval, sd->delta, dir, sd->bigger, sd->smaller);
01452             else {
01453                 if(sd->sarea) {
01454                     sd->sarea->flag &= ~(AREA_FLAG_DRAWSPLIT_H|AREA_FLAG_DRAWSPLIT_V);
01455                     ED_area_tag_redraw(sd->sarea);
01456                 }
01457                 sd->sarea= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);  /* area context not set */
01458                 
01459                 if(sd->sarea) {
01460                     ED_area_tag_redraw(sd->sarea);
01461                     if (dir=='v') {
01462                         sd->origsize= sd->sarea->winx;
01463                         sd->origmin= sd->sarea->totrct.xmin;
01464                         sd->sarea->flag |= AREA_FLAG_DRAWSPLIT_V;
01465                     }
01466                     else {
01467                         sd->origsize= sd->sarea->winy;
01468                         sd->origmin= sd->sarea->totrct.ymin;
01469                         sd->sarea->flag |= AREA_FLAG_DRAWSPLIT_H;
01470                     }
01471                 }
01472                 
01473                 CTX_wm_window(C)->screen->do_draw= 1;
01474 
01475             }
01476             
01477             fac= (dir == 'v') ? event->x-sd->origmin : event->y-sd->origmin;
01478             RNA_float_set(op->ptr, "factor", fac / (float)sd->origsize);
01479             
01480             break;
01481             
01482         case LEFTMOUSE:
01483             if(sd->previewmode) {
01484                 area_split_apply(C, op);
01485                 area_split_exit(C, op);
01486                 return OPERATOR_FINISHED;
01487             }
01488             else {
01489                 if(event->val==KM_RELEASE) { /* mouse up */
01490                     area_split_exit(C, op);
01491                     return OPERATOR_FINISHED;
01492                 }
01493             }
01494             break;
01495             
01496         case MIDDLEMOUSE:
01497         case TABKEY:
01498             if (sd->previewmode==0){
01499             }
01500             else{
01501                 dir = RNA_enum_get(op->ptr, "direction");
01502                 
01503                 if(event->val==KM_PRESS){
01504                     if (sd->sarea){
01505                         sd->sarea->flag &= ~(AREA_FLAG_DRAWSPLIT_H|AREA_FLAG_DRAWSPLIT_V);
01506                         ED_area_tag_redraw(sd->sarea);
01507                         
01508                         if (dir=='v'){
01509                             RNA_enum_set(op->ptr, "direction", 'h');
01510                             sd->sarea->flag |= AREA_FLAG_DRAWSPLIT_H;
01511                             
01512                             WM_cursor_set(CTX_wm_window(C),CURSOR_X_MOVE);
01513                         }
01514                         else{
01515                             RNA_enum_set(op->ptr, "direction", 'v');
01516                             sd->sarea->flag |= AREA_FLAG_DRAWSPLIT_V;
01517                             
01518                             WM_cursor_set(CTX_wm_window(C),CURSOR_Y_MOVE);
01519                         }
01520                     }
01521                 }
01522             }
01523             
01524             break;
01525             
01526         case RIGHTMOUSE: /* cancel operation */
01527         case ESCKEY:
01528             return area_split_cancel(C, op);
01529     }
01530     
01531     return OPERATOR_RUNNING_MODAL;
01532 }
01533 
01534 static EnumPropertyItem prop_direction_items[] = {
01535 {'h', "HORIZONTAL", 0, "Horizontal", ""},
01536 {'v', "VERTICAL", 0, "Vertical", ""},
01537 {0, NULL, 0, NULL, NULL}};
01538 
01539 static void SCREEN_OT_area_split(wmOperatorType *ot)
01540 {
01541     ot->name = "Split area";
01542     ot->description= "Split selected area into new windows";
01543     ot->idname = "SCREEN_OT_area_split";
01544     
01545     ot->exec= area_split_exec;
01546     ot->invoke= area_split_invoke;
01547     ot->modal= area_split_modal;
01548     ot->cancel= area_split_cancel;
01549     
01550     ot->poll= screen_active_editable;
01551     ot->flag= OPTYPE_BLOCKING;
01552     
01553     /* rna */
01554     RNA_def_enum(ot->srna, "direction", prop_direction_items, 'h', "Direction", "");
01555     RNA_def_float(ot->srna, "factor", 0.5f, 0.0, 1.0, "Factor", "", 0.0, 1.0);
01556     RNA_def_int(ot->srna, "mouse_x", -100, INT_MIN, INT_MAX, "Mouse X", "", INT_MIN, INT_MAX);
01557     RNA_def_int(ot->srna, "mouse_y", -100, INT_MIN, INT_MAX, "Mouse Y", "", INT_MIN, INT_MAX);
01558 }
01559 
01560 
01561 
01562 /* ************** scale region edge operator *********************************** */
01563 
01564 typedef struct RegionMoveData {
01565     AZone *az;
01566     ARegion *ar;
01567     ScrArea *sa;
01568     int bigger, smaller, origval;
01569     int origx, origy;
01570     int maxsize;
01571     AZEdge edge;
01572     
01573 } RegionMoveData;
01574 
01575 
01576 static int area_max_regionsize(ScrArea *sa, ARegion *scalear, AZEdge edge)
01577 {
01578     ARegion *ar;
01579     int dist;
01580     
01581     if(edge==AE_RIGHT_TO_TOPLEFT || edge==AE_LEFT_TO_TOPRIGHT) {
01582         dist = sa->totrct.xmax - sa->totrct.xmin;
01583     } else {    /* AE_BOTTOM_TO_TOPLEFT, AE_TOP_TO_BOTTOMRIGHT */
01584         dist = sa->totrct.ymax - sa->totrct.ymin;
01585     }
01586     
01587     /* subtractwidth of regions on opposite side 
01588      * prevents dragging regions into other opposite regions */
01589     for (ar=sa->regionbase.first; ar; ar=ar->next) {
01590         if (ar == scalear)
01591             continue;
01592         
01593         if (scalear->alignment == RGN_ALIGN_TOP && ar->alignment == RGN_ALIGN_BOTTOM)
01594             dist -= ar->winy;
01595         else if (scalear->alignment == RGN_ALIGN_BOTTOM && ar->alignment == RGN_ALIGN_TOP)
01596             dist -= ar->winy;
01597         else if (scalear->alignment == RGN_ALIGN_LEFT && ar->alignment == RGN_ALIGN_RIGHT)
01598             dist -= ar->winx;
01599         else if (scalear->alignment == RGN_ALIGN_RIGHT && ar->alignment == RGN_ALIGN_LEFT)
01600             dist -= ar->winx;
01601         
01602         /* case of regions in regions, like operator properties panel */
01603         /* these can sit on top of other regions such as headers, so account for this */
01604         else if (edge == AE_BOTTOM_TO_TOPLEFT && scalear->alignment & RGN_ALIGN_TOP && ar->alignment == RGN_ALIGN_TOP && ar->regiontype == RGN_TYPE_HEADER)
01605             dist -= ar->winy;
01606         else if (edge == AE_TOP_TO_BOTTOMRIGHT && scalear->alignment & RGN_ALIGN_BOTTOM && ar->alignment == RGN_ALIGN_BOTTOM && ar->regiontype == RGN_TYPE_HEADER)
01607             dist -= ar->winy;
01608     }
01609 
01610     return dist;
01611 }
01612 
01613 static int region_scale_invoke(bContext *C, wmOperator *op, wmEvent *event)
01614 {
01615     sActionzoneData *sad= event->customdata;
01616     AZone *az;
01617     
01618     if(event->type!=EVT_ACTIONZONE_REGION) {
01619         BKE_report(op->reports, RPT_ERROR, "Can only scale region size from an action zone");   
01620         return OPERATOR_CANCELLED;
01621     }
01622     
01623     az = sad->az;
01624     
01625     if(az->ar) {
01626         RegionMoveData *rmd= MEM_callocN(sizeof(RegionMoveData), "RegionMoveData");
01627         int maxsize;
01628         
01629         op->customdata= rmd;
01630         
01631         rmd->az = az;
01632         rmd->ar= az->ar;
01633         rmd->sa = sad->sa1;
01634         rmd->edge= az->edge;
01635         rmd->origx= event->x;
01636         rmd->origy= event->y;
01637         rmd->maxsize = area_max_regionsize(rmd->sa, rmd->ar, rmd->edge);
01638         
01639         /* if not set we do now, otherwise it uses type */
01640         if(rmd->ar->sizex==0) 
01641             rmd->ar->sizex= rmd->ar->type->prefsizex;
01642         if(rmd->ar->sizey==0) 
01643             rmd->ar->sizey= rmd->ar->type->prefsizey;
01644         
01645         /* now copy to regionmovedata */
01646         if(rmd->edge==AE_LEFT_TO_TOPRIGHT || rmd->edge==AE_RIGHT_TO_TOPLEFT) {
01647             rmd->origval= rmd->ar->sizex;
01648         } else {
01649             rmd->origval= rmd->ar->sizey;
01650         }
01651         
01652         /* limit headers to standard height for now */
01653         if (rmd->ar->regiontype == RGN_TYPE_HEADER)
01654             maxsize = rmd->ar->type->prefsizey;
01655         else
01656             maxsize = 1000;
01657         
01658         CLAMP(rmd->maxsize, 0, maxsize);
01659         
01660         /* add temp handler */
01661         WM_event_add_modal_handler(C, op);
01662         
01663         return OPERATOR_RUNNING_MODAL;
01664     }
01665     
01666     return OPERATOR_FINISHED;
01667 }
01668 
01669 static int region_scale_get_maxsize(RegionMoveData *rmd)
01670 {
01671     int maxsize= 0;
01672 
01673     if(rmd->edge==AE_LEFT_TO_TOPRIGHT || rmd->edge==AE_RIGHT_TO_TOPLEFT) {
01674         return rmd->sa->winx - UI_UNIT_X;
01675     }
01676 
01677     if(rmd->ar->regiontype == RGN_TYPE_TOOL_PROPS) {
01678         /* this calculation seems overly verbose
01679          * can someone explain why this method is necessary? - campbell */
01680         maxsize = rmd->maxsize - ((rmd->sa->headertype==HEADERTOP)?UI_UNIT_Y*2:UI_UNIT_Y) - (UI_UNIT_Y/4);
01681     }
01682 
01683     return maxsize;
01684 }
01685 
01686 static void region_scale_validate_size(RegionMoveData *rmd)
01687 {
01688     if((rmd->ar->flag & RGN_FLAG_HIDDEN)==0) {
01689         short *size, maxsize= -1;
01690 
01691 
01692         if(rmd->edge==AE_LEFT_TO_TOPRIGHT || rmd->edge==AE_RIGHT_TO_TOPLEFT)
01693             size= &rmd->ar->sizex;
01694         else
01695             size= &rmd->ar->sizey;
01696 
01697         maxsize= region_scale_get_maxsize(rmd);
01698 
01699         if(*size > maxsize && maxsize > 0)
01700             *size= maxsize;
01701     }
01702 }
01703 
01704 static void region_scale_toggle_hidden(bContext *C, RegionMoveData *rmd)
01705 {
01706     ED_region_toggle_hidden(C, rmd->ar);
01707     region_scale_validate_size(rmd);
01708 }
01709 
01710 static int region_scale_modal(bContext *C, wmOperator *op, wmEvent *event)
01711 {
01712     RegionMoveData *rmd= op->customdata;
01713     int delta;
01714     
01715     /* execute the events */
01716     switch(event->type) {
01717         case MOUSEMOVE:
01718             
01719             if(rmd->edge==AE_LEFT_TO_TOPRIGHT || rmd->edge==AE_RIGHT_TO_TOPLEFT) {
01720                 delta= event->x - rmd->origx;
01721                 if(rmd->edge==AE_LEFT_TO_TOPRIGHT) delta= -delta;
01722                 
01723                 rmd->ar->sizex= rmd->origval + delta;
01724                 CLAMP(rmd->ar->sizex, 0, rmd->maxsize);
01725                 
01726                 if(rmd->ar->sizex < UI_UNIT_X) {
01727                     rmd->ar->sizex= rmd->origval;
01728                     if(!(rmd->ar->flag & RGN_FLAG_HIDDEN))
01729                         region_scale_toggle_hidden(C, rmd);
01730                 }
01731                 else if(rmd->ar->flag & RGN_FLAG_HIDDEN)
01732                     region_scale_toggle_hidden(C, rmd);
01733             }
01734             else {
01735                 int maxsize= region_scale_get_maxsize(rmd);
01736                 delta= event->y - rmd->origy;
01737                 if(rmd->edge==AE_BOTTOM_TO_TOPLEFT) delta= -delta;
01738                 
01739                 rmd->ar->sizey= rmd->origval + delta;
01740                 CLAMP(rmd->ar->sizey, 0, rmd->maxsize);
01741 
01742                 /* note, 'UI_UNIT_Y/4' means you need to drag the header almost
01743                  * all the way down for it to become hidden, this is done
01744                  * otherwise its too easy to do this by accident */
01745                 if(rmd->ar->sizey < UI_UNIT_Y/4) {
01746                     rmd->ar->sizey= rmd->origval;
01747                     if(!(rmd->ar->flag & RGN_FLAG_HIDDEN))
01748                         region_scale_toggle_hidden(C, rmd);
01749                 }
01750                 else if(maxsize > 0 && (rmd->ar->sizey > maxsize)) 
01751                     rmd->ar->sizey= maxsize;
01752                 else if(rmd->ar->flag & RGN_FLAG_HIDDEN)
01753                     region_scale_toggle_hidden(C, rmd);
01754             }
01755             ED_area_tag_redraw(rmd->sa);
01756             WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
01757             
01758             break;
01759             
01760         case LEFTMOUSE:
01761             if(event->val==KM_RELEASE) {
01762                 
01763                 if(ABS(event->x - rmd->origx) < 2 && ABS(event->y - rmd->origy) < 2) {
01764                     if(rmd->ar->flag & RGN_FLAG_HIDDEN) {
01765                         region_scale_toggle_hidden(C, rmd);
01766                     }
01767                     else if(rmd->ar->flag & RGN_FLAG_TOO_SMALL) {
01768                         region_scale_validate_size(rmd);
01769                     }
01770 
01771                     ED_area_tag_redraw(rmd->sa);
01772                     WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
01773                 }
01774                 MEM_freeN(op->customdata);
01775                 op->customdata = NULL;
01776                 
01777                 return OPERATOR_FINISHED;
01778             }
01779             break;
01780             
01781         case ESCKEY:
01782             ;
01783     }
01784     
01785     return OPERATOR_RUNNING_MODAL;
01786 }
01787 
01788 static int region_scale_cancel(bContext *UNUSED(C), wmOperator *op)
01789 {
01790     MEM_freeN(op->customdata);
01791     op->customdata = NULL;
01792 
01793     return OPERATOR_CANCELLED;
01794 }
01795 
01796 static void SCREEN_OT_region_scale(wmOperatorType *ot)
01797 {
01798     /* identifiers */
01799     ot->name= "Scale Region Size";
01800     ot->description= "Scale selected area";
01801     ot->idname= "SCREEN_OT_region_scale";
01802     
01803     ot->invoke= region_scale_invoke;
01804     ot->modal= region_scale_modal;
01805     ot->cancel= region_scale_cancel;
01806     
01807     ot->poll= ED_operator_areaactive;
01808     
01809     ot->flag= OPTYPE_BLOCKING;
01810 }
01811 
01812 
01813 /* ************** frame change operator ***************************** */
01814 
01815 /* function to be called outside UI context, or for redo */
01816 static int frame_offset_exec(bContext *C, wmOperator *op)
01817 {
01818     Main *bmain= CTX_data_main(C);
01819     Scene *scene= CTX_data_scene(C);
01820     int delta;
01821     
01822     delta = RNA_int_get(op->ptr, "delta");
01823 
01824     scene->r.cfra += delta;
01825     scene->r.subframe = 0.f;
01826     
01827     sound_seek_scene(bmain, scene);
01828 
01829     WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
01830     
01831     return OPERATOR_FINISHED;
01832 }
01833 
01834 static void SCREEN_OT_frame_offset(wmOperatorType *ot)
01835 {
01836     ot->name = "Frame Offset";
01837     ot->idname = "SCREEN_OT_frame_offset";
01838     
01839     ot->exec= frame_offset_exec;
01840     
01841     ot->poll= ED_operator_screenactive_norender;
01842     ot->flag= 0;
01843     
01844     /* rna */
01845     RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
01846 }
01847 
01848 
01849 /* function to be called outside UI context, or for redo */
01850 static int frame_jump_exec(bContext *C, wmOperator *op)
01851 {
01852     Main *bmain= CTX_data_main(C);
01853     Scene *scene= CTX_data_scene(C);
01854     wmTimer *animtimer= CTX_wm_screen(C)->animtimer;
01855 
01856     /* Don't change CFRA directly if animtimer is running as this can cause
01857      * first/last frame not to be actually shown (bad since for example physics
01858      * simulations aren't reset properly).
01859      */
01860     if(animtimer) {
01861         ScreenAnimData *sad = animtimer->customdata;
01862         
01863         sad->flag |= ANIMPLAY_FLAG_USE_NEXT_FRAME;
01864         
01865         if (RNA_boolean_get(op->ptr, "end"))
01866             sad->nextfra= PEFRA;
01867         else
01868             sad->nextfra= PSFRA;
01869     }
01870     else {
01871         if (RNA_boolean_get(op->ptr, "end"))
01872             CFRA= PEFRA;
01873         else
01874             CFRA= PSFRA;
01875         
01876         sound_seek_scene(bmain, scene);
01877 
01878         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
01879     }
01880     
01881     return OPERATOR_FINISHED;
01882 }
01883 
01884 static void SCREEN_OT_frame_jump(wmOperatorType *ot)
01885 {
01886     ot->name = "Jump to Endpoint";
01887     ot->description= "Jump to first/last frame in frame range";
01888     ot->idname = "SCREEN_OT_frame_jump";
01889     
01890     ot->exec= frame_jump_exec;
01891     
01892     ot->poll= ED_operator_screenactive_norender;
01893     ot->flag= OPTYPE_UNDO;
01894     
01895     /* rna */
01896     RNA_def_boolean(ot->srna, "end", 0, "Last Frame", "Jump to the last frame of the frame range");
01897 }
01898 
01899 
01900 /* ************** jump to keyframe operator ***************************** */
01901 
01902 /* function to be called outside UI context, or for redo */
01903 static int keyframe_jump_exec(bContext *C, wmOperator *op)
01904 {
01905     Main *bmain= CTX_data_main(C);
01906     Scene *scene= CTX_data_scene(C);
01907     Object *ob= CTX_data_active_object(C);
01908     bDopeSheet ads= {NULL};
01909     DLRBT_Tree keys;
01910     ActKeyColumn *ak;
01911     float cfra;
01912     short next= RNA_boolean_get(op->ptr, "next");
01913     short done = 0;
01914     
01915     /* sanity checks */
01916     if (scene == NULL)
01917         return OPERATOR_CANCELLED;
01918 
01919     cfra= (float)(CFRA);
01920 
01921     /* init binarytree-list for getting keyframes */
01922     BLI_dlrbTree_init(&keys);
01923     
01924     /* populate tree with keyframe nodes */
01925     scene_to_keylist(&ads, scene, &keys, NULL);
01926 
01927     if (ob)
01928         ob_to_keylist(&ads, ob, &keys, NULL);
01929     
01930     /* build linked-list for searching */
01931     BLI_dlrbTree_linkedlist_sync(&keys);
01932     
01933     /* find matching keyframe in the right direction */
01934     do {
01935         if (next)
01936             ak= (ActKeyColumn *)BLI_dlrbTree_search_next(&keys, compare_ak_cfraPtr, &cfra);
01937         else
01938             ak= (ActKeyColumn *)BLI_dlrbTree_search_prev(&keys, compare_ak_cfraPtr, &cfra);
01939         
01940         if (ak) {
01941             if (CFRA != (int)ak->cfra) {
01942                 /* this changes the frame, so set the frame and we're done */
01943                 CFRA= (int)ak->cfra;
01944                 done = 1;
01945             }
01946             else {
01947                 /* make this the new starting point for the search */
01948                 cfra = ak->cfra;
01949             }
01950         }
01951     } while ((ak != NULL) && (done == 0));
01952     
01953     /* any success? */
01954     if (done == 0)
01955         BKE_report(op->reports, RPT_INFO, "No more keyframes to jump to in this direction");
01956     
01957     /* free temp stuff */
01958     BLI_dlrbTree_free(&keys);
01959     
01960     sound_seek_scene(bmain, scene);
01961 
01962     WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
01963     
01964     return OPERATOR_FINISHED;
01965 }
01966 
01967 static void SCREEN_OT_keyframe_jump(wmOperatorType *ot)
01968 {
01969     ot->name = "Jump to Keyframe";
01970     ot->description= "Jump to previous/next keyframe";
01971     ot->idname = "SCREEN_OT_keyframe_jump";
01972     
01973     ot->exec= keyframe_jump_exec;
01974     
01975     ot->poll= ED_operator_screenactive_norender;
01976     ot->flag= OPTYPE_UNDO;
01977     
01978     /* rna */
01979     RNA_def_boolean(ot->srna, "next", 1, "Next Keyframe", "");
01980 }
01981 
01982 /* ************** switch screen operator ***************************** */
01983 
01984 
01985 /* function to be called outside UI context, or for redo */
01986 static int screen_set_exec(bContext *C, wmOperator *op)
01987 {
01988     bScreen *screen= CTX_wm_screen(C);
01989     bScreen *screen_prev= screen;
01990     
01991     ScrArea *sa= CTX_wm_area(C);
01992     int tot= BLI_countlist(&CTX_data_main(C)->screen);
01993     int delta= RNA_int_get(op->ptr, "delta");
01994     
01995     /* temp screens are for userpref or render display */
01996     if(screen->temp)
01997         return OPERATOR_CANCELLED;
01998     
01999     if(delta==1) {
02000         while(tot--) {
02001             screen= screen->id.next;
02002             if(screen==NULL) screen= CTX_data_main(C)->screen.first;
02003             if(screen->winid==0 && screen->full==0 && screen != screen_prev)
02004                 break;
02005         }
02006     }
02007     else if(delta== -1) {
02008         while(tot--) {
02009             screen= screen->id.prev;
02010             if(screen==NULL) screen= CTX_data_main(C)->screen.last;
02011             if(screen->winid==0 && screen->full==0 && screen != screen_prev)
02012                 break;
02013         }
02014     }
02015     else {
02016         screen= NULL;
02017     }
02018     
02019     if(screen && screen_prev != screen) {
02020         /* return to previous state before switching screens */
02021         if(sa && sa->full) {
02022             ED_screen_full_restore(C, sa); /* may free 'screen_prev' */
02023         }
02024         
02025         ED_screen_set(C, screen);
02026         return OPERATOR_FINISHED;
02027     }
02028     return OPERATOR_CANCELLED;
02029 }
02030 
02031 static void SCREEN_OT_screen_set(wmOperatorType *ot)
02032 {
02033     ot->name = "Set Screen";
02034     ot->description= "Cycle through available screens";
02035     ot->idname = "SCREEN_OT_screen_set";
02036     
02037     ot->exec= screen_set_exec;
02038     ot->poll= ED_operator_screenactive;
02039     
02040     /* rna */
02041     RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
02042 }
02043 
02044 /* ************** screen full-area operator ***************************** */
02045 
02046 
02047 /* function to be called outside UI context, or for redo */
02048 static int screen_full_area_exec(bContext *C, wmOperator *UNUSED(op))
02049 {
02050     bScreen *screen = CTX_wm_screen(C);
02051     ScrArea *sa=NULL;
02052     
02053     /* search current screen for 'fullscreen' areas */
02054     /* prevents restoring info header, when mouse is over it */
02055     for (sa=screen->areabase.first; sa; sa=sa->next) {
02056         if (sa->full) break;
02057     }
02058     
02059     if(sa==NULL) sa= CTX_wm_area(C);
02060     
02061     ED_screen_full_toggle(C, CTX_wm_window(C), sa);
02062     return OPERATOR_FINISHED;
02063 }
02064 
02065 static void SCREEN_OT_screen_full_area(wmOperatorType *ot)
02066 {
02067     ot->name = "Toggle Full Screen";
02068     ot->description= "Toggle display selected area as fullscreen";
02069     ot->idname = "SCREEN_OT_screen_full_area";
02070     
02071     ot->exec= screen_full_area_exec;
02072     ot->poll= ED_operator_areaactive;
02073     ot->flag= 0;
02074     
02075 }
02076 
02077 
02078 
02079 /* ************** join area operator ********************************************** */
02080 
02081 /* operator state vars used:  
02082  x1, y1     mouse coord in first area, which will disappear
02083  x2, y2     mouse coord in 2nd area, which will become joined
02084  
02085  functions:
02086  
02087  init()   find edge based on state vars 
02088  test if the edge divides two areas, 
02089  store active and nonactive area,
02090  
02091  apply()  do the actual join
02092  
02093  exit() cleanup, send notifier
02094  
02095  callbacks:
02096  
02097  exec() calls init, apply, exit 
02098  
02099  invoke() sets mouse coords in x,y
02100  call init()
02101  add modal handler
02102  
02103  modal()    accept modal events while doing it
02104  call apply() with active window and nonactive window
02105  call exit() and remove handler when LMB confirm
02106  
02107  */
02108 
02109 typedef struct sAreaJoinData
02110 {
02111     ScrArea *sa1;   /* first area to be considered */
02112     ScrArea *sa2;   /* second area to be considered */
02113     ScrArea *scr;   /* designed for removal */
02114 
02115 } sAreaJoinData;
02116 
02117 
02118 /* validate selection inside screen, set variables OK */
02119 /* return 0: init failed */
02120 /* XXX todo: find edge based on (x,y) and set other area? */
02121 static int area_join_init(bContext *C, wmOperator *op)
02122 {
02123     ScrArea *sa1, *sa2;
02124     sAreaJoinData* jd= NULL;
02125     int x1, y1;
02126     int x2, y2;
02127     int shared= 0;
02128     
02129     /* required properties, make negative to get return 0 if not set by caller */
02130     x1= RNA_int_get(op->ptr, "min_x");
02131     y1= RNA_int_get(op->ptr, "min_y");
02132     x2= RNA_int_get(op->ptr, "max_x");
02133     y2= RNA_int_get(op->ptr, "max_y");
02134     
02135     sa1 = screen_areahascursor(CTX_wm_screen(C), x1, y1);
02136     sa2 = screen_areahascursor(CTX_wm_screen(C), x2, y2);
02137     if(sa1==NULL || sa2==NULL || sa1==sa2)
02138         return 0;
02139     
02140     /* do areas share an edge? */
02141     if(sa1->v1==sa2->v1 || sa1->v1==sa2->v2 || sa1->v1==sa2->v3 || sa1->v1==sa2->v4) shared++; 
02142     if(sa1->v2==sa2->v1 || sa1->v2==sa2->v2 || sa1->v2==sa2->v3 || sa1->v2==sa2->v4) shared++; 
02143     if(sa1->v3==sa2->v1 || sa1->v3==sa2->v2 || sa1->v3==sa2->v3 || sa1->v3==sa2->v4) shared++; 
02144     if(sa1->v4==sa2->v1 || sa1->v4==sa2->v2 || sa1->v4==sa2->v3 || sa1->v4==sa2->v4) shared++; 
02145     if(shared!=2) {
02146         printf("areas don't share edge\n");
02147         return 0;
02148     }
02149     
02150     jd = (sAreaJoinData*)MEM_callocN(sizeof (sAreaJoinData), "op_area_join");
02151     
02152     jd->sa1 = sa1;
02153     jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
02154     jd->sa2 = sa2;
02155     jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
02156     
02157     op->customdata= jd;
02158     
02159     return 1;
02160 }
02161 
02162 /* apply the join of the areas (space types) */
02163 static int area_join_apply(bContext *C, wmOperator *op)
02164 {
02165     sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
02166     if (!jd) return 0;
02167     
02168     if(!screen_area_join(C, CTX_wm_screen(C), jd->sa1, jd->sa2)){
02169         return 0;
02170     }
02171     if (CTX_wm_area(C) == jd->sa2) {
02172         CTX_wm_area_set(C, NULL);
02173         CTX_wm_region_set(C, NULL);
02174     }
02175     
02176     return 1;
02177 }
02178 
02179 /* finish operation */
02180 static void area_join_exit(bContext *C, wmOperator *op)
02181 {
02182     if (op->customdata) {
02183         MEM_freeN(op->customdata);
02184         op->customdata = NULL;
02185     }
02186     
02187     /* this makes sure aligned edges will result in aligned grabbing */
02188     removedouble_scredges(CTX_wm_screen(C));
02189     removenotused_scredges(CTX_wm_screen(C));
02190     removenotused_scrverts(CTX_wm_screen(C));
02191 }
02192 
02193 static int area_join_exec(bContext *C, wmOperator *op)
02194 {
02195     if(!area_join_init(C, op)) 
02196         return OPERATOR_CANCELLED;
02197     
02198     area_join_apply(C, op);
02199     area_join_exit(C, op);
02200     
02201     return OPERATOR_FINISHED;
02202 }
02203 
02204 /* interaction callback */
02205 static int area_join_invoke(bContext *C, wmOperator *op, wmEvent *event)
02206 {
02207     
02208     if(event->type==EVT_ACTIONZONE_AREA) {
02209         sActionzoneData *sad= event->customdata;
02210         
02211         if(sad->modifier>0) {
02212             return OPERATOR_PASS_THROUGH;
02213         }
02214         
02215         /* verify *sad itself */
02216         if(sad==NULL || sad->sa1==NULL || sad->sa2==NULL)
02217             return OPERATOR_PASS_THROUGH;
02218         
02219         /* is this our *sad? if areas equal it should be passed on */
02220         if(sad->sa1==sad->sa2)
02221             return OPERATOR_PASS_THROUGH;
02222         
02223         /* prepare operator state vars */
02224         RNA_int_set(op->ptr, "min_x", sad->x);
02225         RNA_int_set(op->ptr, "min_y", sad->y);
02226         RNA_int_set(op->ptr, "max_x", event->x);
02227         RNA_int_set(op->ptr, "max_y", event->y);
02228     }
02229     
02230     
02231     if(!area_join_init(C, op)) 
02232         return OPERATOR_PASS_THROUGH;
02233     
02234     /* add temp handler */
02235     WM_event_add_modal_handler(C, op);
02236     
02237     return OPERATOR_RUNNING_MODAL;
02238 }
02239 
02240 static int area_join_cancel(bContext *C, wmOperator *op)
02241 {
02242     sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
02243     
02244     if (jd->sa1) {
02245         jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
02246         jd->sa1->flag &= ~AREA_FLAG_DRAWJOINTO;
02247     }
02248     if (jd->sa2) {
02249         jd->sa2->flag &= ~AREA_FLAG_DRAWJOINFROM;
02250         jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
02251     }
02252     
02253     WM_event_add_notifier(C, NC_WINDOW, NULL);
02254     
02255     area_join_exit(C, op);
02256     
02257     return OPERATOR_CANCELLED;
02258 }
02259 
02260 /* modal callback while selecting area (space) that will be removed */
02261 static int area_join_modal(bContext *C, wmOperator *op, wmEvent *event)
02262 {
02263     bScreen *sc= CTX_wm_screen(C);
02264     sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
02265     
02266     /* execute the events */
02267     switch(event->type) {
02268             
02269         case MOUSEMOVE: 
02270         {
02271             ScrArea *sa = screen_areahascursor(sc, event->x, event->y);
02272             int dir;
02273             
02274             if (sa) {                   
02275                 if (jd->sa1 != sa) {
02276                     dir = area_getorientation(jd->sa1, sa);
02277                     if (dir >= 0) {
02278                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
02279                         jd->sa2 = sa;
02280                         jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
02281                     } 
02282                     else {
02283                         /* we are not bordering on the previously selected area 
02284                          we check if area has common border with the one marked for removal
02285                          in this case we can swap areas.
02286                          */
02287                         dir = area_getorientation(sa, jd->sa2);
02288                         if (dir >= 0) {
02289                             if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
02290                             if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
02291                             jd->sa1 = jd->sa2;
02292                             jd->sa2 = sa;
02293                             if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
02294                             if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
02295                         } 
02296                         else {
02297                             if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
02298                             jd->sa2 = NULL;
02299                         }
02300                     }
02301                     WM_event_add_notifier(C, NC_WINDOW, NULL);
02302                 } 
02303                 else {
02304                     /* we are back in the area previously selected for keeping 
02305                      * we swap the areas if possible to allow user to choose */
02306                     if (jd->sa2 != NULL) {
02307                         if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
02308                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
02309                         jd->sa1 = jd->sa2;
02310                         jd->sa2 = sa;
02311                         if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
02312                         if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
02313                         dir = area_getorientation(jd->sa1, jd->sa2);
02314                         if (dir < 0) {
02315                             printf("oops, didn't expect that!\n");
02316                         }
02317                     } 
02318                     else {
02319                         dir = area_getorientation(jd->sa1, sa);
02320                         if (dir >= 0) {
02321                             if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
02322                             jd->sa2 = sa;
02323                             jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
02324                         }
02325                     }
02326                     WM_event_add_notifier(C, NC_WINDOW, NULL);
02327                 }
02328             }
02329         }
02330             break;
02331         case LEFTMOUSE:
02332             if(event->val==KM_RELEASE) {
02333                 ED_area_tag_redraw(jd->sa1);
02334                 ED_area_tag_redraw(jd->sa2);
02335 
02336                 area_join_apply(C, op);
02337                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
02338                 area_join_exit(C, op);
02339                 return OPERATOR_FINISHED;
02340             }
02341             break;
02342             
02343         case RIGHTMOUSE:
02344         case ESCKEY:
02345             return area_join_cancel(C, op);
02346     }
02347     
02348     return OPERATOR_RUNNING_MODAL;
02349 }
02350 
02351 /* Operator for joining two areas (space types) */
02352 static void SCREEN_OT_area_join(wmOperatorType *ot)
02353 {
02354     /* identifiers */
02355     ot->name= "Join area";
02356     ot->description= "Join selected areas into new window";
02357     ot->idname= "SCREEN_OT_area_join";
02358     
02359     /* api callbacks */
02360     ot->exec= area_join_exec;
02361     ot->invoke= area_join_invoke;
02362     ot->modal= area_join_modal;
02363     ot->poll= screen_active_editable;
02364     ot->cancel= area_join_cancel;
02365     
02366     ot->flag= OPTYPE_BLOCKING|OPTYPE_INTERNAL;
02367     
02368     /* rna */
02369     RNA_def_int(ot->srna, "min_x", -100, INT_MIN, INT_MAX, "X 1", "", INT_MIN, INT_MAX);
02370     RNA_def_int(ot->srna, "min_y", -100, INT_MIN, INT_MAX, "Y 1", "", INT_MIN, INT_MAX);
02371     RNA_def_int(ot->srna, "max_x", -100, INT_MIN, INT_MAX, "X 2", "", INT_MIN, INT_MAX);
02372     RNA_def_int(ot->srna, "max_y", -100, INT_MIN, INT_MAX, "Y 2", "", INT_MIN, INT_MAX);
02373 }
02374 
02375 /* ******************************* */
02376 
02377 static int screen_area_options_invoke(bContext *C, wmOperator *op, wmEvent *event)
02378 {
02379     uiPopupMenu *pup;
02380     uiLayout *layout;
02381     PointerRNA ptr1, ptr2;
02382     ScrEdge *actedge= screen_find_active_scredge(CTX_wm_screen(C), event->x, event->y);
02383     
02384     if(actedge==NULL) return OPERATOR_CANCELLED;
02385     
02386     pup= uiPupMenuBegin(C, op->type->name, ICON_NONE);
02387     layout= uiPupMenuLayout(pup);
02388     
02389     WM_operator_properties_create(&ptr1, "SCREEN_OT_area_join");
02390     
02391     /* mouse cursor on edge, '4' can fail on wide edges... */
02392     RNA_int_set(&ptr1, "min_x", event->x+4);
02393     RNA_int_set(&ptr1, "min_y", event->y+4);
02394     RNA_int_set(&ptr1, "max_x", event->x-4);
02395     RNA_int_set(&ptr1, "max_y", event->y-4);
02396     
02397     WM_operator_properties_create(&ptr2, "SCREEN_OT_area_split");
02398     
02399     /* store initial mouse cursor position */
02400     RNA_int_set(&ptr2, "mouse_x", event->x);
02401     RNA_int_set(&ptr2, "mouse_y", event->y);
02402     
02403     uiItemFullO(layout, "SCREEN_OT_area_split", "Split Area", ICON_NONE, ptr2.data, WM_OP_INVOKE_DEFAULT, 0);
02404     uiItemFullO(layout, "SCREEN_OT_area_join", "Join Area", ICON_NONE, ptr1.data, WM_OP_INVOKE_DEFAULT, 0);
02405     
02406     uiPupMenuEnd(C, pup);
02407     
02408     return OPERATOR_CANCELLED;
02409 }
02410 
02411 static void SCREEN_OT_area_options(wmOperatorType *ot)
02412 {
02413     /* identifiers */
02414     ot->name= "Area Options";
02415     ot->description= "Operations for splitting and merging";
02416     ot->idname= "SCREEN_OT_area_options";
02417     
02418     /* api callbacks */
02419     ot->invoke= screen_area_options_invoke;
02420     
02421     ot->poll= ED_operator_screen_mainwinactive;
02422 }
02423 
02424 
02425 /* ******************************* */
02426 
02427 
02428 static int spacedata_cleanup(bContext *C, wmOperator *op)
02429 {
02430     Main *bmain= CTX_data_main(C);
02431     bScreen *screen;
02432     ScrArea *sa;
02433     int tot= 0;
02434     
02435     for(screen= bmain->screen.first; screen; screen= screen->id.next) {
02436         for(sa= screen->areabase.first; sa; sa= sa->next) {
02437             if(sa->spacedata.first != sa->spacedata.last) {
02438                 SpaceLink *sl= sa->spacedata.first;
02439 
02440                 BLI_remlink(&sa->spacedata, sl);
02441                 tot+= BLI_countlist(&sa->spacedata);
02442                 BKE_spacedata_freelist(&sa->spacedata);
02443                 BLI_addtail(&sa->spacedata, sl);
02444             }
02445         }
02446     }
02447     BKE_reportf(op->reports, RPT_INFO, "Removed amount of editors: %d", tot);
02448     
02449     return OPERATOR_FINISHED;
02450 }
02451 
02452 static void SCREEN_OT_spacedata_cleanup(wmOperatorType *ot)
02453 {
02454     /* identifiers */
02455     ot->name= "Clean-up space-data";
02456     ot->description= "Remove unused settings for invisible editors";
02457     ot->idname= "SCREEN_OT_spacedata_cleanup";
02458     
02459     /* api callbacks */
02460     ot->exec= spacedata_cleanup;
02461     ot->poll= WM_operator_winactive;
02462     
02463 }
02464 
02465 /* ************** repeat last operator ***************************** */
02466 
02467 static int repeat_last_exec(bContext *C, wmOperator *UNUSED(op))
02468 {
02469     wmOperator *lastop= CTX_wm_manager(C)->operators.last;
02470     
02471     if(lastop)
02472         WM_operator_repeat(C, lastop);
02473     
02474     return OPERATOR_CANCELLED;
02475 }
02476 
02477 static void SCREEN_OT_repeat_last(wmOperatorType *ot)
02478 {
02479     /* identifiers */
02480     ot->name= "Repeat Last";
02481     ot->description= "Repeat last action";
02482     ot->idname= "SCREEN_OT_repeat_last";
02483     
02484     /* api callbacks */
02485     ot->exec= repeat_last_exec;
02486     
02487     ot->poll= ED_operator_screenactive;
02488     
02489 }
02490 
02491 static int repeat_history_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
02492 {
02493     wmWindowManager *wm= CTX_wm_manager(C);
02494     wmOperator *lastop;
02495     uiPopupMenu *pup;
02496     uiLayout *layout;
02497     int items, i;
02498     
02499     items= BLI_countlist(&wm->operators);
02500     if(items==0)
02501         return OPERATOR_CANCELLED;
02502     
02503     pup= uiPupMenuBegin(C, op->type->name, ICON_NONE);
02504     layout= uiPupMenuLayout(pup);
02505     
02506     for (i=items-1, lastop= wm->operators.last; lastop; lastop= lastop->prev, i--)
02507         uiItemIntO(layout, lastop->type->name, ICON_NONE, op->type->idname, "index", i);
02508     
02509     uiPupMenuEnd(C, pup);
02510     
02511     return OPERATOR_CANCELLED;
02512 }
02513 
02514 static int repeat_history_exec(bContext *C, wmOperator *op)
02515 {
02516     wmWindowManager *wm= CTX_wm_manager(C);
02517     
02518     op= BLI_findlink(&wm->operators, RNA_int_get(op->ptr, "index"));
02519     if(op) {
02520         /* let's put it as last operator in list */
02521         BLI_remlink(&wm->operators, op);
02522         BLI_addtail(&wm->operators, op);
02523         
02524         WM_operator_repeat(C, op);
02525     }
02526     
02527     return OPERATOR_FINISHED;
02528 }
02529 
02530 static void SCREEN_OT_repeat_history(wmOperatorType *ot)
02531 {
02532     /* identifiers */
02533     ot->name= "Repeat History";
02534     ot->description= "Display menu for previous actions performed";
02535     ot->idname= "SCREEN_OT_repeat_history";
02536     
02537     /* api callbacks */
02538     ot->invoke= repeat_history_invoke;
02539     ot->exec= repeat_history_exec;
02540     
02541     ot->poll= ED_operator_screenactive;
02542     
02543     RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
02544 }
02545 
02546 /* ********************** redo operator ***************************** */
02547 
02548 static int redo_last_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
02549 {
02550     wmOperator *lastop= WM_operator_last_redo(C);
02551     
02552     if(lastop)
02553         WM_operator_redo_popup(C, lastop);
02554     
02555     return OPERATOR_CANCELLED;
02556 }
02557 
02558 static void SCREEN_OT_redo_last(wmOperatorType *ot)
02559 {
02560     /* identifiers */
02561     ot->name= "Redo Last";
02562     ot->description= "Display menu for last action performed";
02563     ot->idname= "SCREEN_OT_redo_last";
02564     
02565     /* api callbacks */
02566     ot->invoke= redo_last_invoke;
02567     
02568     ot->poll= ED_operator_screenactive;
02569 }
02570 
02571 /* ************** region four-split operator ***************************** */
02572 
02573 /* insert a region in the area region list */
02574 static int region_quadview_exec(bContext *C, wmOperator *op)
02575 {
02576     ARegion *ar= CTX_wm_region(C);
02577     
02578     /* some rules... */
02579     if(ar->regiontype!=RGN_TYPE_WINDOW)
02580         BKE_report(op->reports, RPT_ERROR, "Only window region can be 4-splitted");
02581     else if(ar->alignment==RGN_ALIGN_QSPLIT) {
02582         ScrArea *sa= CTX_wm_area(C);
02583         ARegion *arn;
02584         
02585         /* keep current region */
02586         ar->alignment= 0;
02587         
02588         if(sa->spacetype==SPACE_VIEW3D) {
02589             RegionView3D *rv3d= ar->regiondata;
02590             rv3d->viewlock= 0;
02591             rv3d->rflag &= ~RV3D_CLIPPING;
02592         }
02593         
02594         for(ar= sa->regionbase.first; ar; ar= arn) {
02595             arn= ar->next;
02596             if(ar->alignment==RGN_ALIGN_QSPLIT) {
02597                 ED_region_exit(C, ar);
02598                 BKE_area_region_free(sa->type, ar);
02599                 BLI_remlink(&sa->regionbase, ar);
02600                 MEM_freeN(ar);
02601             }
02602         }
02603         ED_area_tag_redraw(sa);
02604         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
02605     }
02606     else if(ar->next)
02607         BKE_report(op->reports, RPT_ERROR, "Only last region can be 4-splitted");
02608     else {
02609         ScrArea *sa= CTX_wm_area(C);
02610         ARegion *newar;
02611         int count;
02612         
02613         ar->alignment= RGN_ALIGN_QSPLIT;
02614         
02615         for(count=0; count<3; count++) {
02616             newar= BKE_area_region_copy(sa->type, ar);
02617             BLI_addtail(&sa->regionbase, newar);
02618         }
02619         
02620         /* lock views and set them */
02621         if(sa->spacetype==SPACE_VIEW3D) {
02622             /* run ED_view3d_lock() so the correct 'rv3d->viewquat' is set,
02623              * otherwise when restoring rv3d->localvd the 'viewquat' won't
02624              * match the 'view', set on entering localview See: [#26315],
02625              *
02626              * We could avoid manipulating rv3d->localvd here if exiting
02627              * localview with a 4-split would assign these view locks */
02628             RegionView3D *rv3d;
02629             
02630             rv3d= ar->regiondata;
02631             rv3d->viewlock= RV3D_LOCKED; rv3d->view= RV3D_VIEW_FRONT; rv3d->persp= RV3D_ORTHO;
02632             ED_view3d_lock(rv3d);
02633             if (rv3d->localvd) { rv3d->localvd->view = rv3d->view; rv3d->localvd->persp = rv3d->persp; copy_qt_qt(rv3d->localvd->viewquat, rv3d->viewquat);}
02634             
02635             ar= ar->next;
02636             rv3d= ar->regiondata;
02637             rv3d->viewlock= RV3D_LOCKED; rv3d->view= RV3D_VIEW_TOP; rv3d->persp= RV3D_ORTHO;
02638             ED_view3d_lock(rv3d);
02639             if (rv3d->localvd) { rv3d->localvd->view = rv3d->view; rv3d->localvd->persp = rv3d->persp; copy_qt_qt(rv3d->localvd->viewquat, rv3d->viewquat);}
02640             
02641             ar= ar->next;
02642             rv3d= ar->regiondata;
02643             rv3d->viewlock= RV3D_LOCKED; rv3d->view= RV3D_VIEW_RIGHT; rv3d->persp= RV3D_ORTHO;
02644             ED_view3d_lock(rv3d);
02645             if (rv3d->localvd) { rv3d->localvd->view = rv3d->view; rv3d->localvd->persp = rv3d->persp; copy_qt_qt(rv3d->localvd->viewquat, rv3d->viewquat);}
02646             
02647             ar= ar->next;
02648             rv3d= ar->regiondata;
02649             rv3d->view= RV3D_VIEW_CAMERA; rv3d->persp= RV3D_CAMOB;
02650             ED_view3d_lock(rv3d);
02651             if (rv3d->localvd) {rv3d->localvd->view = rv3d->view; rv3d->localvd->persp = rv3d->persp; copy_qt_qt(rv3d->localvd->viewquat, rv3d->viewquat);}
02652         }
02653         ED_area_tag_redraw(sa);
02654         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
02655     }
02656     
02657     
02658     return OPERATOR_FINISHED;
02659 }
02660 
02661 static void SCREEN_OT_region_quadview(wmOperatorType *ot)
02662 {
02663     /* identifiers */
02664     ot->name= "Toggle Quad View";
02665     ot->description= "Split selected area into camera, front, right & top views";
02666     ot->idname= "SCREEN_OT_region_quadview";
02667     
02668     /* api callbacks */
02669     //  ot->invoke= WM_operator_confirm;
02670     ot->exec= region_quadview_exec;
02671     ot->poll= ED_operator_region_view3d_active;
02672     ot->flag= 0;
02673 }
02674 
02675 
02676 
02677 /* ************** region flip operator ***************************** */
02678 
02679 /* flip a region alignment */
02680 static int region_flip_exec(bContext *C, wmOperator *UNUSED(op))
02681 {
02682     ARegion *ar= CTX_wm_region(C);
02683     
02684     if (!ar)
02685         return OPERATOR_CANCELLED;
02686     
02687     if(ar->alignment==RGN_ALIGN_TOP)
02688         ar->alignment= RGN_ALIGN_BOTTOM;
02689     else if(ar->alignment==RGN_ALIGN_BOTTOM)
02690         ar->alignment= RGN_ALIGN_TOP;
02691     else if(ar->alignment==RGN_ALIGN_LEFT)
02692         ar->alignment= RGN_ALIGN_RIGHT;
02693     else if(ar->alignment==RGN_ALIGN_RIGHT)
02694         ar->alignment= RGN_ALIGN_LEFT;
02695 
02696     ED_area_tag_redraw(CTX_wm_area(C));
02697     WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
02698     
02699     return OPERATOR_FINISHED;
02700 }
02701 
02702 
02703 static void SCREEN_OT_region_flip(wmOperatorType *ot)
02704 {
02705     /* identifiers */
02706     ot->name= "Flip Region";
02707     ot->idname= "SCREEN_OT_region_flip";
02708     
02709     /* api callbacks */
02710     ot->exec= region_flip_exec;
02711     ot->poll= ED_operator_areaactive;
02712     ot->flag= 0;
02713 }
02714 
02715 /* ************** header flip operator ***************************** */
02716 
02717 /* flip a header region alignment */
02718 static int header_flip_exec(bContext *C, wmOperator *UNUSED(op))
02719 {
02720     ARegion *ar= CTX_wm_region(C);
02721     
02722     /* find the header region 
02723      *  - try context first, but upon failing, search all regions in area...
02724      */
02725     if((ar == NULL) || (ar->regiontype != RGN_TYPE_HEADER)) {
02726         ScrArea *sa= CTX_wm_area(C);
02727         ar= BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
02728 
02729         /* don't do anything if no region */
02730         if(ar == NULL)
02731             return OPERATOR_CANCELLED;
02732     }   
02733     
02734     /* copied from SCREEN_OT_region_flip */
02735     if(ar->alignment==RGN_ALIGN_TOP)
02736         ar->alignment= RGN_ALIGN_BOTTOM;
02737     else if(ar->alignment==RGN_ALIGN_BOTTOM)
02738         ar->alignment= RGN_ALIGN_TOP;
02739     else if(ar->alignment==RGN_ALIGN_LEFT)
02740         ar->alignment= RGN_ALIGN_RIGHT;
02741     else if(ar->alignment==RGN_ALIGN_RIGHT)
02742         ar->alignment= RGN_ALIGN_LEFT;
02743 
02744     ED_area_tag_redraw(CTX_wm_area(C));
02745 
02746     WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
02747     
02748     return OPERATOR_FINISHED;
02749 }
02750 
02751 
02752 static void SCREEN_OT_header_flip(wmOperatorType *ot)
02753 {
02754     /* identifiers */
02755     ot->name= "Flip Header Region";
02756     ot->idname= "SCREEN_OT_header_flip";
02757     
02758     /* api callbacks */
02759     ot->exec= header_flip_exec;
02760     
02761     ot->poll= ED_operator_areaactive;
02762     ot->flag= 0;
02763 }
02764 
02765 /* ************** header tools operator ***************************** */
02766 
02767 static int header_toolbox_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
02768 {
02769     ScrArea *sa= CTX_wm_area(C);
02770     ARegion *ar= CTX_wm_region(C);
02771     uiPopupMenu *pup;
02772     uiLayout *layout;
02773     
02774     pup= uiPupMenuBegin(C, "Header", ICON_NONE);
02775     layout= uiPupMenuLayout(pup);
02776     
02777     // XXX SCREEN_OT_region_flip doesn't work - gets wrong context for active region, so added custom operator
02778     if (ar->alignment == RGN_ALIGN_TOP)
02779         uiItemO(layout, "Flip to Bottom", ICON_NONE, "SCREEN_OT_header_flip");
02780     else
02781         uiItemO(layout, "Flip to Top", ICON_NONE, "SCREEN_OT_header_flip");
02782     
02783     uiItemS(layout);
02784     
02785     /* file browser should be fullscreen all the time, but other regions can be maximised/restored... */
02786     if (sa->spacetype != SPACE_FILE) {
02787         if (sa->full) 
02788             uiItemO(layout, "Tile Area", ICON_NONE, "SCREEN_OT_screen_full_area");
02789         else
02790             uiItemO(layout, "Maximize Area", ICON_NONE, "SCREEN_OT_screen_full_area");
02791     }
02792     
02793     uiPupMenuEnd(C, pup);
02794     
02795     return OPERATOR_CANCELLED;
02796 }
02797 
02798 static void SCREEN_OT_header_toolbox(wmOperatorType *ot)
02799 {
02800     /* identifiers */
02801     ot->name= "Header Toolbox";
02802     ot->description="Display header region toolbox";
02803     ot->idname= "SCREEN_OT_header_toolbox";
02804     
02805     /* api callbacks */
02806     ot->invoke= header_toolbox_invoke;
02807 }
02808 
02809 /* ****************** anim player, with timer ***************** */
02810 
02811 static int match_area_with_refresh(int spacetype, int refresh)
02812 {
02813     switch (spacetype) {
02814         case SPACE_TIME:
02815             if (refresh & SPACE_TIME)
02816                 return 1;
02817             break;
02818     }
02819     
02820     return 0;
02821 }
02822 
02823 static int match_region_with_redraws(int spacetype, int regiontype, int redraws)
02824 {
02825     if(regiontype==RGN_TYPE_WINDOW) {
02826         
02827         switch (spacetype) {
02828             case SPACE_VIEW3D:
02829                 if(redraws & TIME_ALL_3D_WIN)
02830                     return 1;
02831                 break;
02832             case SPACE_IPO:
02833             case SPACE_ACTION:
02834             case SPACE_NLA:
02835                 if(redraws & TIME_ALL_ANIM_WIN)
02836                     return 1;
02837                 break;
02838             case SPACE_TIME:
02839                 /* if only 1 window or 3d windows, we do timeline too */
02840                 if(redraws & (TIME_ALL_ANIM_WIN|TIME_REGION|TIME_ALL_3D_WIN))
02841                     return 1;
02842                 break;
02843             case SPACE_BUTS:
02844                 if(redraws & TIME_ALL_BUTS_WIN)
02845                     return 1;
02846                 break;
02847             case SPACE_SEQ:
02848                 if(redraws & (TIME_SEQ|TIME_ALL_ANIM_WIN))
02849                     return 1;
02850                 break;
02851             case SPACE_NODE:
02852                 if(redraws & (TIME_NODES))
02853                     return 1;
02854                 break;
02855             case SPACE_IMAGE:
02856                 if(redraws & TIME_ALL_IMAGE_WIN)
02857                     return 1;
02858                 break;
02859             case SPACE_CLIP:
02860                 if(redraws & TIME_CLIPS)
02861                     return 1;
02862                 break;
02863                 
02864         }
02865     }
02866     else if(regiontype==RGN_TYPE_UI) {
02867         if(spacetype==SPACE_CLIP) {
02868             /* Track Preview button is on Properties Editor in SpaceClip,
02869                and it's very common case when users want it be refreshing
02870                during playback, so asking people to enable special option
02871                for this is a bit ticky, so add exception here for refreshing
02872                Properties Editor for SpaceClip always */
02873             return 1;
02874         }
02875 
02876         if(redraws & TIME_ALL_BUTS_WIN)
02877             return 1;
02878     }
02879     else if(regiontype==RGN_TYPE_HEADER) {
02880         if(spacetype==SPACE_TIME)
02881             return 1;
02882     }
02883     else if (regiontype==RGN_TYPE_PREVIEW) {
02884         switch (spacetype) {
02885             case SPACE_SEQ:
02886                 if(redraws & (TIME_SEQ|TIME_ALL_ANIM_WIN))
02887                     return 1;
02888                 break;
02889             case SPACE_CLIP:
02890                 return 1;
02891         }
02892     }
02893     return 0;
02894 }
02895 
02896 static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
02897 {
02898     bScreen *screen= CTX_wm_screen(C);
02899 
02900     if(screen->animtimer && screen->animtimer==event->customdata) {
02901         Main *bmain= CTX_data_main(C);
02902         Scene *scene= CTX_data_scene(C);
02903         wmTimer *wt= screen->animtimer;
02904         ScreenAnimData *sad= wt->customdata;
02905         ScrArea *sa;
02906         int sync;
02907         float time;
02908         
02909         /* sync, don't sync, or follow scene setting */
02910         if (sad->flag & ANIMPLAY_FLAG_SYNC) sync= 1;
02911         else if (sad->flag & ANIMPLAY_FLAG_NO_SYNC) sync= 0;
02912         else sync= (scene->flag & SCE_FRAME_DROP);
02913         
02914         if((scene->audio.flag & AUDIO_SYNC) && !(sad->flag & ANIMPLAY_FLAG_REVERSE) && finite(time = sound_sync_scene(scene)))
02915             scene->r.cfra = (double)time * FPS + 0.5;
02916         else
02917         {
02918             if (sync) {
02919                 int step = floor(wt->duration * FPS);
02920                 /* skip frames */
02921                 if (sad->flag & ANIMPLAY_FLAG_REVERSE)
02922                     scene->r.cfra -= step;
02923                 else
02924                     scene->r.cfra += step;
02925                 wt->duration -= ((double)step)/FPS;
02926             }
02927             else {
02928                 /* one frame +/- */
02929                 if (sad->flag & ANIMPLAY_FLAG_REVERSE)
02930                     scene->r.cfra--;
02931                 else
02932                     scene->r.cfra++;
02933             }
02934         }
02935         
02936         /* reset 'jumped' flag before checking if we need to jump... */
02937         sad->flag &= ~ANIMPLAY_FLAG_JUMPED;
02938         
02939         if (sad->flag & ANIMPLAY_FLAG_REVERSE) {
02940             /* jump back to end? */
02941             if (PRVRANGEON) {
02942                 if (scene->r.cfra < scene->r.psfra) {
02943                     scene->r.cfra= scene->r.pefra;
02944                     sad->flag |= ANIMPLAY_FLAG_JUMPED;
02945                 }
02946             }
02947             else {
02948                 if (scene->r.cfra < scene->r.sfra) {
02949                     scene->r.cfra= scene->r.efra;
02950                     sad->flag |= ANIMPLAY_FLAG_JUMPED;
02951                 }
02952             }
02953         }
02954         else {
02955             /* jump back to start? */
02956             if (PRVRANGEON) {
02957                 if (scene->r.cfra > scene->r.pefra) {
02958                     scene->r.cfra= scene->r.psfra;
02959                     sad->flag |= ANIMPLAY_FLAG_JUMPED;
02960                 }
02961             }
02962             else {
02963                 if (scene->r.cfra > scene->r.efra) {
02964                     scene->r.cfra= scene->r.sfra;
02965                     sad->flag |= ANIMPLAY_FLAG_JUMPED;
02966                 }
02967             }
02968         }
02969 
02970         /* next frame overriden by user action (pressed jump to first/last frame) */
02971         if(sad->flag & ANIMPLAY_FLAG_USE_NEXT_FRAME) {
02972             scene->r.cfra = sad->nextfra;
02973             sad->flag &= ~ANIMPLAY_FLAG_USE_NEXT_FRAME;
02974             sad->flag |= ANIMPLAY_FLAG_JUMPED;
02975         }
02976         
02977         if (sad->flag & ANIMPLAY_FLAG_JUMPED)
02978             sound_seek_scene(bmain, scene);
02979         
02980         /* since we follow drawflags, we can't send notifier but tag regions ourselves */
02981         ED_update_for_newframe(CTX_data_main(C), scene, screen, 1);
02982         
02983         for (sa= screen->areabase.first; sa; sa= sa->next) {
02984             ARegion *ar;
02985             for (ar= sa->regionbase.first; ar; ar= ar->next) {
02986                 if (ar==sad->ar)
02987                     ED_region_tag_redraw(ar);
02988                 else
02989                     if (match_region_with_redraws(sa->spacetype, ar->regiontype, sad->redraws))
02990                         ED_region_tag_redraw(ar);
02991             }
02992             
02993             if (match_area_with_refresh(sa->spacetype, sad->refresh))
02994                 ED_area_tag_refresh(sa);
02995         }
02996         
02997         /* update frame rate info too 
02998          * NOTE: this may not be accurate enough, since we might need this after modifiers/etc. 
02999          * have been calculated instead of just before updates have been done?
03000          */
03001         ED_refresh_viewport_fps(C);
03002         
03003         /* recalculate the timestep for the timer now that we've finished calculating this,
03004          * since the frames-per-second value may have been changed
03005          */
03006         // TODO: this may make evaluation a bit slower if the value doesn't change... any way to avoid this?
03007         wt->timestep= (1.0/FPS);
03008         
03009         return OPERATOR_FINISHED;
03010     }
03011     return OPERATOR_PASS_THROUGH;
03012 }
03013 
03014 static void SCREEN_OT_animation_step(wmOperatorType *ot)
03015 {
03016     /* identifiers */
03017     ot->name= "Animation Step";
03018     ot->description= "Step through animation by position";
03019     ot->idname= "SCREEN_OT_animation_step";
03020     
03021     /* api callbacks */
03022     ot->invoke= screen_animation_step;
03023     
03024     ot->poll= ED_operator_screenactive_norender;
03025     
03026 }
03027 
03028 /* ****************** anim player, starts or ends timer ***************** */
03029 
03030 /* toggle operator */
03031 int ED_screen_animation_play(bContext *C, int sync, int mode)
03032 {
03033     bScreen *screen= CTX_wm_screen(C);
03034     Scene *scene = CTX_data_scene(C);
03035 
03036     if (screen->animtimer) {
03037         /* stop playback now */
03038         ED_screen_animation_timer(C, 0, 0, 0, 0);
03039         sound_stop_scene(scene);
03040     }
03041     else {
03042         int refresh= SPACE_TIME; /* these settings are currently only available from a menu in the TimeLine */
03043         
03044         if (mode == 1) // XXX only play audio forwards!?
03045             sound_play_scene(scene);
03046         
03047         ED_screen_animation_timer(C, screen->redraws_flag, refresh, sync, mode);
03048         
03049         if (screen->animtimer) {
03050             wmTimer *wt= screen->animtimer;
03051             ScreenAnimData *sad= wt->customdata;
03052             
03053             sad->ar= CTX_wm_region(C);
03054         }
03055     }
03056 
03057     return OPERATOR_FINISHED;
03058 }
03059 
03060 static int screen_animation_play_exec(bContext *C, wmOperator *op)
03061 {
03062     int mode= (RNA_boolean_get(op->ptr, "reverse")) ? -1 : 1;
03063     int sync= -1;
03064     
03065     if (RNA_struct_property_is_set(op->ptr, "sync"))
03066         sync= (RNA_boolean_get(op->ptr, "sync"));
03067     
03068     return ED_screen_animation_play(C, sync, mode);
03069 }
03070 
03071 static void SCREEN_OT_animation_play(wmOperatorType *ot)
03072 {
03073     /* identifiers */
03074     ot->name= "Play Animation";
03075     ot->description= "Play animation";
03076     ot->idname= "SCREEN_OT_animation_play";
03077     
03078     /* api callbacks */
03079     ot->exec= screen_animation_play_exec;
03080     
03081     ot->poll= ED_operator_screenactive_norender;
03082     
03083     RNA_def_boolean(ot->srna, "reverse", 0, "Play in Reverse", "Animation is played backwards");
03084     RNA_def_boolean(ot->srna, "sync", 0, "Sync", "Drop frames to maintain framerate");
03085 }
03086 
03087 static int screen_animation_cancel_exec(bContext *C, wmOperator *op)
03088 {
03089     bScreen *screen= CTX_wm_screen(C);
03090 
03091     if (screen->animtimer) {
03092         if(RNA_boolean_get(op->ptr, "restore_frame")) {
03093             ScreenAnimData *sad= screen->animtimer->customdata;
03094             Scene *scene= CTX_data_scene(C);
03095 
03096             /* reset current frame before stopping, and just send a notifier to deal with the rest
03097              * (since playback still needs to be stopped)
03098              */
03099             scene->r.cfra= sad->sfra;
03100 
03101             WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
03102         }
03103 
03104         /* call the other "toggling" operator to clean up now */
03105         ED_screen_animation_play(C, 0, 0);
03106     }
03107 
03108     return OPERATOR_PASS_THROUGH;
03109 }
03110 
03111 static void SCREEN_OT_animation_cancel(wmOperatorType *ot)
03112 {
03113     /* identifiers */
03114     ot->name= "Cancel Animation";
03115     ot->description= "Cancel animation, returning to the original frame";
03116     ot->idname= "SCREEN_OT_animation_cancel";
03117     
03118     /* api callbacks */
03119     ot->exec= screen_animation_cancel_exec;
03120     
03121     ot->poll= ED_operator_screenactive;
03122 
03123     RNA_def_boolean(ot->srna, "restore_frame", TRUE, "Restore Frame", "Restore the frame when animation was initialized");
03124 }
03125 
03126 /* ************** border select operator (template) ***************************** */
03127 
03128 /* operator state vars used: (added by default WM callbacks)   
03129  xmin, ymin     
03130  xmax, ymax     
03131  
03132  customdata: the wmGesture pointer
03133  
03134  callbacks:
03135  
03136  exec() has to be filled in by user
03137  
03138  invoke() default WM function
03139  adds modal handler
03140  
03141  modal()    default WM function 
03142  accept modal events while doing it, calls exec(), handles ESC and border drawing
03143  
03144  poll() has to be filled in by user for context
03145  */
03146 #if 0
03147 static int border_select_do(bContext *C, wmOperator *op)
03148 {
03149     int event_type= RNA_int_get(op->ptr, "event_type");
03150     
03151     if(event_type==LEFTMOUSE)
03152         printf("border select do select\n");
03153     else if(event_type==RIGHTMOUSE)
03154         printf("border select deselect\n");
03155     else 
03156         printf("border select do something\n");
03157     
03158     return 1;
03159 }
03160 
03161 static void SCREEN_OT_border_select(wmOperatorType *ot)
03162 {
03163     /* identifiers */
03164     ot->name= "Border select";
03165     ot->idname= "SCREEN_OT_border_select";
03166     
03167     /* api callbacks */
03168     ot->exec= border_select_do;
03169     ot->invoke= WM_border_select_invoke;
03170     ot->modal= WM_border_select_modal;
03171     ot->cancel= WM_border_select_cancel;
03172     
03173     ot->poll= ED_operator_areaactive;
03174     
03175     /* rna */
03176     RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
03177     RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
03178     RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
03179     RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
03180     RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
03181     
03182 }
03183 #endif
03184 
03185 /* *********************** generic fullscreen 'back' button *************** */
03186 
03187 
03188 static int fullscreen_back_exec(bContext *C, wmOperator *op)
03189 {
03190     bScreen *screen = CTX_wm_screen(C);
03191     ScrArea *sa=NULL;
03192     
03193     /* search current screen for 'fullscreen' areas */
03194     for (sa=screen->areabase.first; sa; sa=sa->next) {
03195         if (sa->full) break;
03196     }
03197     if (!sa) {
03198         BKE_report(op->reports, RPT_ERROR, "No fullscreen areas were found");
03199         return OPERATOR_CANCELLED;
03200     }
03201     
03202     ED_screen_full_restore(C, sa);
03203     
03204     return OPERATOR_FINISHED;
03205 }
03206 
03207 static void SCREEN_OT_back_to_previous(struct wmOperatorType *ot)
03208 {
03209     /* identifiers */
03210     ot->name= "Back to Previous Screen";
03211     ot->description= "Revert back to the original screen layout, before fullscreen area overlay";
03212     ot->idname= "SCREEN_OT_back_to_previous";
03213     
03214     /* api callbacks */
03215     ot->exec= fullscreen_back_exec;
03216     ot->poll= ED_operator_screenactive;
03217 }
03218 
03219 /* *********** show user pref window ****** */
03220 
03221 static int userpref_show_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
03222 {
03223     rcti rect;
03224     int sizex, sizey;
03225     
03226     sizex= 800;
03227     sizey= 480;
03228     
03229     /* some magic to calculate postition */
03230     rect.xmin= event->x + CTX_wm_window(C)->posx - sizex/2;
03231     rect.ymin= event->y + CTX_wm_window(C)->posy - sizey/2;
03232     rect.xmax= rect.xmin + sizex;
03233     rect.ymax= rect.ymin + sizey;
03234     
03235     /* changes context! */
03236     WM_window_open_temp(C, &rect, WM_WINDOW_USERPREFS);
03237     
03238     return OPERATOR_FINISHED;
03239 }
03240 
03241 
03242 static void SCREEN_OT_userpref_show(struct wmOperatorType *ot)
03243 {
03244     /* identifiers */
03245     ot->name= "Show/Hide User Preferences";
03246     ot->description= "Show/hide user preferences";
03247     ot->idname= "SCREEN_OT_userpref_show";
03248     
03249     /* api callbacks */
03250     ot->invoke= userpref_show_invoke;
03251     ot->poll= ED_operator_screenactive;
03252 }
03253 
03254 /********************* new screen operator *********************/
03255 
03256 static int screen_new_exec(bContext *C, wmOperator *UNUSED(op))
03257 {
03258     wmWindow *win= CTX_wm_window(C);
03259     bScreen *sc= CTX_wm_screen(C);
03260     
03261     sc= ED_screen_duplicate(win, sc);
03262     WM_event_add_notifier(C, NC_SCREEN|ND_SCREENBROWSE, sc);
03263     
03264     return OPERATOR_FINISHED;
03265 }
03266 
03267 static void SCREEN_OT_new(wmOperatorType *ot)
03268 {
03269     /* identifiers */
03270     ot->name= "New Screen";
03271     ot->description= "Add a new screen";
03272     ot->idname= "SCREEN_OT_new";
03273     
03274     /* api callbacks */
03275     ot->exec= screen_new_exec;
03276     ot->poll= WM_operator_winactive;
03277     
03278     /* flags */
03279     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
03280 }
03281 
03282 /********************* delete screen operator *********************/
03283 
03284 static int screen_delete_exec(bContext *C, wmOperator *UNUSED(op))
03285 {
03286     bScreen *sc= CTX_wm_screen(C);
03287     
03288     WM_event_add_notifier(C, NC_SCREEN|ND_SCREENDELETE, sc);
03289     
03290     return OPERATOR_FINISHED;
03291 }
03292 
03293 static void SCREEN_OT_delete(wmOperatorType *ot)
03294 {
03295     /* identifiers */
03296     ot->name= "Delete Screen"; //was scene
03297     ot->description= "Delete active screen";
03298     ot->idname= "SCREEN_OT_delete";
03299     
03300     /* api callbacks */
03301     ot->exec= screen_delete_exec;
03302     
03303     /* flags */
03304     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
03305 }
03306 
03307 /********************* new scene operator *********************/
03308 
03309 static int scene_new_exec(bContext *C, wmOperator *op)
03310 {
03311     Scene *newscene, *scene= CTX_data_scene(C);
03312     Main *bmain= CTX_data_main(C);
03313     int type= RNA_enum_get(op->ptr, "type");
03314 
03315     if(type == SCE_COPY_NEW) {
03316         newscene= add_scene("Scene");
03317     }
03318     else { /* different kinds of copying */
03319         newscene= copy_scene(scene, type);
03320 
03321         /* these can't be handled in blenkernel curently, so do them here */
03322         if(type == SCE_COPY_LINK_DATA) {
03323             ED_object_single_users(bmain, newscene, 0);
03324         }
03325         else if(type == SCE_COPY_FULL) {
03326             ED_object_single_users(bmain, newscene, 1);
03327         }
03328     }
03329     
03330     ED_screen_set_scene(C, newscene);
03331     
03332     WM_event_add_notifier(C, NC_SCENE|ND_SCENEBROWSE, newscene);
03333     
03334     return OPERATOR_FINISHED;
03335 }
03336 
03337 static void SCENE_OT_new(wmOperatorType *ot)
03338 {
03339     static EnumPropertyItem type_items[]= {
03340         {SCE_COPY_NEW, "NEW", 0, "New", "Add new scene"},
03341         {SCE_COPY_EMPTY, "EMPTY", 0, "Copy Settings", "Make a copy without any objects"},
03342         {SCE_COPY_LINK_OB, "LINK_OBJECTS", 0, "Link Objects", "Link to the objects from the current scene"},
03343         {SCE_COPY_LINK_DATA, "LINK_OBJECT_DATA", 0, "Link Object Data", "Copy objects linked to data from the current scene"},
03344         {SCE_COPY_FULL, "FULL_COPY", 0, "Full Copy", "Make a full copy of the current scene"},
03345         {0, NULL, 0, NULL, NULL}};
03346     
03347     /* identifiers */
03348     ot->name= "New Scene";
03349     ot->description= "Add new scene by type";
03350     ot->idname= "SCENE_OT_new";
03351     
03352     /* api callbacks */
03353     ot->exec= scene_new_exec;
03354     ot->invoke= WM_menu_invoke;
03355     
03356     /* flags */
03357     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
03358     
03359     /* properties */
03360     ot->prop= RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
03361 }
03362 
03363 /********************* delete scene operator *********************/
03364 
03365 static int scene_delete_exec(bContext *C, wmOperator *UNUSED(op))
03366 {
03367     Scene *scene= CTX_data_scene(C);
03368 
03369     ED_screen_delete_scene(C, scene);
03370 
03371     if(G.f & G_DEBUG)
03372         printf("scene delete %p\n", scene);
03373 
03374     WM_event_add_notifier(C, NC_SCENE|NA_REMOVED, scene);
03375 
03376     return OPERATOR_FINISHED;
03377 }
03378 
03379 static void SCENE_OT_delete(wmOperatorType *ot)
03380 {
03381     /* identifiers */
03382     ot->name= "Delete Scene";
03383     ot->description= "Delete active scene";
03384     ot->idname= "SCENE_OT_delete";
03385     
03386     /* api callbacks */
03387     ot->exec= scene_delete_exec;
03388     
03389     /* flags */
03390     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
03391 }
03392 
03393 /* ****************  Assigning operatortypes to global list, adding handlers **************** */
03394 
03395 
03396 /* called in spacetypes.c */
03397 void ED_operatortypes_screen(void)
03398 {
03399     /* generic UI stuff */
03400     WM_operatortype_append(SCREEN_OT_actionzone);
03401     WM_operatortype_append(SCREEN_OT_repeat_last);
03402     WM_operatortype_append(SCREEN_OT_repeat_history);
03403     WM_operatortype_append(SCREEN_OT_redo_last);
03404     
03405     /* screen tools */
03406     WM_operatortype_append(SCREEN_OT_area_move);
03407     WM_operatortype_append(SCREEN_OT_area_split);
03408     WM_operatortype_append(SCREEN_OT_area_join);
03409     WM_operatortype_append(SCREEN_OT_area_options);
03410     WM_operatortype_append(SCREEN_OT_area_dupli);
03411     WM_operatortype_append(SCREEN_OT_area_swap);
03412     WM_operatortype_append(SCREEN_OT_region_quadview);
03413     WM_operatortype_append(SCREEN_OT_region_scale);
03414     WM_operatortype_append(SCREEN_OT_region_flip);
03415     WM_operatortype_append(SCREEN_OT_header_flip);
03416     WM_operatortype_append(SCREEN_OT_header_toolbox);
03417     WM_operatortype_append(SCREEN_OT_screen_set);
03418     WM_operatortype_append(SCREEN_OT_screen_full_area);
03419     WM_operatortype_append(SCREEN_OT_back_to_previous);
03420     WM_operatortype_append(SCREEN_OT_spacedata_cleanup);
03421     WM_operatortype_append(SCREEN_OT_screenshot);
03422     WM_operatortype_append(SCREEN_OT_screencast);
03423     WM_operatortype_append(SCREEN_OT_userpref_show);
03424     
03425     /*frame changes*/
03426     WM_operatortype_append(SCREEN_OT_frame_offset);
03427     WM_operatortype_append(SCREEN_OT_frame_jump);
03428     WM_operatortype_append(SCREEN_OT_keyframe_jump);
03429     
03430     WM_operatortype_append(SCREEN_OT_animation_step);
03431     WM_operatortype_append(SCREEN_OT_animation_play);
03432     WM_operatortype_append(SCREEN_OT_animation_cancel);
03433     
03434     /* new/delete */
03435     WM_operatortype_append(SCREEN_OT_new);
03436     WM_operatortype_append(SCREEN_OT_delete);
03437     WM_operatortype_append(SCENE_OT_new);
03438     WM_operatortype_append(SCENE_OT_delete);
03439     
03440     /* tools shared by more space types */
03441     WM_operatortype_append(ED_OT_undo);
03442     WM_operatortype_append(ED_OT_undo_push);
03443     WM_operatortype_append(ED_OT_redo); 
03444     WM_operatortype_append(ED_OT_undo_history);
03445     
03446 }
03447 
03448 static void keymap_modal_set(wmKeyConfig *keyconf)
03449 {
03450     static EnumPropertyItem modal_items[] = {
03451         {KM_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
03452         {KM_MODAL_APPLY, "APPLY", 0, "Apply", ""},
03453         {KM_MODAL_STEP10, "STEP10", 0, "Steps on", ""},
03454         {KM_MODAL_STEP10_OFF, "STEP10_OFF", 0, "Steps off", ""},
03455         {0, NULL, 0, NULL, NULL}};
03456     wmKeyMap *keymap;
03457     
03458     /* Standard Modal keymap ------------------------------------------------ */
03459     keymap= WM_modalkeymap_add(keyconf, "Standard Modal Map", modal_items);
03460     
03461     WM_modalkeymap_add_item(keymap, ESCKEY,    KM_PRESS, KM_ANY, 0, KM_MODAL_CANCEL);
03462     WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_ANY, KM_ANY, 0, KM_MODAL_APPLY);
03463     WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_APPLY);
03464     WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, KM_MODAL_APPLY);
03465     
03466     WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_STEP10);
03467     WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, KM_MODAL_STEP10_OFF);
03468     
03469     WM_modalkeymap_assign(keymap, "SCREEN_OT_area_move");
03470     
03471 }
03472 
03473 static int open_file_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event))
03474 {
03475     if(drag->type==WM_DRAG_PATH) {
03476         if(drag->icon==ICON_FILE_BLEND)
03477             return 1;
03478     }
03479     return 0;
03480 }
03481 
03482 static void open_file_drop_copy(wmDrag *drag, wmDropBox *drop)
03483 {
03484     /* copy drag path to properties */
03485     RNA_string_set(drop->ptr, "filepath", drag->path);
03486     drop->opcontext= WM_OP_EXEC_DEFAULT;
03487 }
03488 
03489 
03490 /* called in spacetypes.c */
03491 void ED_keymap_screen(wmKeyConfig *keyconf)
03492 {
03493     ListBase *lb;
03494     wmKeyMap *keymap;
03495     wmKeyMapItem *kmi;
03496     
03497     /* Screen Editing ------------------------------------------------ */
03498     keymap= WM_keymap_find(keyconf, "Screen Editing", 0, 0);
03499     
03500     RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "modifier", 0);
03501     RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "modifier", 1);
03502     RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "modifier", 2);
03503     
03504     /* screen tools */
03505     WM_keymap_verify_item(keymap, "SCREEN_OT_area_split", EVT_ACTIONZONE_AREA, 0, 0, 0);
03506     WM_keymap_verify_item(keymap, "SCREEN_OT_area_join", EVT_ACTIONZONE_AREA, 0, 0, 0);
03507     WM_keymap_verify_item(keymap, "SCREEN_OT_area_dupli", EVT_ACTIONZONE_AREA, 0, KM_SHIFT, 0);
03508     WM_keymap_verify_item(keymap, "SCREEN_OT_area_swap", EVT_ACTIONZONE_AREA, 0, KM_CTRL, 0);
03509     WM_keymap_verify_item(keymap, "SCREEN_OT_region_scale", EVT_ACTIONZONE_REGION, 0, 0, 0);
03510     /* area move after action zones */
03511     WM_keymap_verify_item(keymap, "SCREEN_OT_area_move", LEFTMOUSE, KM_PRESS, 0, 0);
03512     
03513     WM_keymap_verify_item(keymap, "SCREEN_OT_area_options", RIGHTMOUSE, KM_PRESS, 0, 0);
03514     
03515     
03516     /* Header Editing ------------------------------------------------ */
03517     keymap= WM_keymap_find(keyconf, "Header", 0, 0);
03518     
03519     WM_keymap_add_item(keymap, "SCREEN_OT_header_toolbox", RIGHTMOUSE, KM_PRESS, 0, 0);
03520     
03521     /* Screen General ------------------------------------------------ */
03522     keymap= WM_keymap_find(keyconf, "Screen", 0, 0);
03523     
03524     /* standard timers */
03525     WM_keymap_add_item(keymap, "SCREEN_OT_animation_step", TIMER0, KM_ANY, KM_ANY, 0);
03526     
03527     
03528     RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", 1);
03529     RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", -1);
03530     WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", UPARROWKEY, KM_PRESS, KM_CTRL, 0);
03531     WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", DOWNARROWKEY, KM_PRESS, KM_CTRL, 0);
03532     WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", SPACEKEY, KM_PRESS, KM_SHIFT, 0);
03533     WM_keymap_add_item(keymap, "SCREEN_OT_screenshot", F3KEY, KM_PRESS, KM_CTRL, 0);
03534     WM_keymap_add_item(keymap, "SCREEN_OT_screencast", F3KEY, KM_PRESS, KM_ALT, 0);
03535     
03536     /* tests */
03537     WM_keymap_add_item(keymap, "SCREEN_OT_region_quadview", QKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
03538     WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_history", F3KEY, KM_PRESS, 0, 0);
03539     WM_keymap_add_item(keymap, "SCREEN_OT_repeat_last", RKEY, KM_PRESS, KM_SHIFT, 0);
03540     WM_keymap_verify_item(keymap, "SCREEN_OT_region_flip", F5KEY, KM_PRESS, 0, 0);
03541     WM_keymap_verify_item(keymap, "SCREEN_OT_redo_last", F6KEY, KM_PRESS, 0, 0);
03542     WM_keymap_verify_item(keymap, "SCRIPT_OT_reload", F8KEY, KM_PRESS, 0, 0);
03543     
03544     /* files */
03545     WM_keymap_add_item(keymap, "FILE_OT_execute", RETKEY, KM_PRESS, 0, 0);
03546     WM_keymap_add_item(keymap, "FILE_OT_execute", PADENTER, KM_PRESS, 0, 0);
03547     WM_keymap_add_item(keymap, "FILE_OT_cancel", ESCKEY, KM_PRESS, 0, 0);
03548     
03549     /* undo */
03550 #ifdef __APPLE__
03551     WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_OSKEY, 0);
03552     WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_OSKEY, 0);
03553     WM_keymap_add_item(keymap, "ED_OT_undo_history", ZKEY, KM_PRESS, KM_ALT|KM_OSKEY, 0);
03554 #endif
03555     WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_CTRL, 0);
03556     WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
03557     WM_keymap_add_item(keymap, "ED_OT_undo_history", ZKEY, KM_PRESS, KM_ALT|KM_CTRL, 0);
03558     
03559     
03560     /* render */
03561     WM_keymap_add_item(keymap, "RENDER_OT_render", F12KEY, KM_PRESS, 0, 0);
03562     kmi = WM_keymap_add_item(keymap, "RENDER_OT_render", F12KEY, KM_PRESS, KM_CTRL, 0);
03563     RNA_boolean_set(kmi->ptr, "animation", TRUE);
03564     WM_keymap_add_item(keymap, "RENDER_OT_view_cancel", ESCKEY, KM_PRESS, 0, 0);
03565     WM_keymap_add_item(keymap, "RENDER_OT_view_show", F11KEY, KM_PRESS, 0, 0);
03566     WM_keymap_add_item(keymap, "RENDER_OT_play_rendered_anim", F11KEY, KM_PRESS, KM_CTRL, 0);
03567     
03568     /* user prefs */
03569 #ifdef __APPLE__
03570     WM_keymap_add_item(keymap, "SCREEN_OT_userpref_show", COMMAKEY, KM_PRESS, KM_OSKEY, 0);
03571 #endif
03572     WM_keymap_add_item(keymap, "SCREEN_OT_userpref_show", UKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
03573     
03574     
03575     /* Anim Playback ------------------------------------------------ */
03576     keymap= WM_keymap_find(keyconf, "Frames", 0, 0);
03577     
03578     /* frame offsets */
03579     RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", UPARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "delta", 10);
03580     RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", DOWNARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "delta", -10);
03581     RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", LEFTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -1);
03582     RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", RIGHTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 1);
03583     
03584     RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", WHEELDOWNMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "delta", 1);
03585     RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", WHEELUPMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "delta", -1);
03586     
03587     RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_jump", UPARROWKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0)->ptr, "end", TRUE);
03588     RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_jump", DOWNARROWKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0)->ptr, "end", FALSE);
03589     RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_jump", RIGHTARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "end", TRUE);
03590     RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_jump", LEFTARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "end", FALSE);
03591     
03592     WM_keymap_add_item(keymap, "SCREEN_OT_keyframe_jump", UPARROWKEY, KM_PRESS, 0, 0);
03593     RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_keyframe_jump", DOWNARROWKEY, KM_PRESS, 0, 0)->ptr, "next", FALSE);
03594     
03595     WM_keymap_add_item(keymap, "SCREEN_OT_keyframe_jump", MEDIALAST, KM_PRESS, 0, 0);
03596     kmi = WM_keymap_add_item(keymap, "SCREEN_OT_keyframe_jump", MEDIAFIRST, KM_PRESS, 0, 0);
03597     RNA_boolean_set(kmi->ptr, "next", FALSE);
03598     
03599     /* play (forward and backwards) */
03600     WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", AKEY, KM_PRESS, KM_ALT, 0);
03601     RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", AKEY, KM_PRESS, KM_ALT|KM_SHIFT, 0)->ptr, "reverse", TRUE);
03602     WM_keymap_add_item(keymap, "SCREEN_OT_animation_cancel", ESCKEY, KM_PRESS, 0, 0);
03603     
03604     WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", MEDIAPLAY, KM_PRESS, 0, 0);
03605     WM_keymap_add_item(keymap, "SCREEN_OT_animation_cancel", MEDIASTOP, KM_PRESS, 0, 0);
03606     
03607     /* Alternative keys for animation and sequencer playing */
03608 #if 0 // XXX: disabled for restoring later... bad implementation
03609     keymap= WM_keymap_find(keyconf, "Frames", 0, 0);
03610     kmi = WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", RIGHTARROWKEY, KM_PRESS, KM_ALT, 0);
03611         RNA_boolean_set(kmi->ptr, "cycle_speed", TRUE);
03612     
03613     kmi = WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", LEFTARROWKEY, KM_PRESS, KM_ALT, 0);
03614         RNA_boolean_set(kmi->ptr, "reverse", TRUE);
03615         RNA_boolean_set(kmi->ptr, "cycle_speed", TRUE);
03616     
03617     WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", DOWNARROWKEY, KM_PRESS, KM_ALT, 0);
03618 #endif
03619 
03620     /* dropbox for entire window */
03621     lb= WM_dropboxmap_find("Window", 0, 0);
03622     WM_dropbox_add(lb, "WM_OT_open_mainfile", open_file_drop_poll, open_file_drop_copy);
03623     
03624     keymap_modal_set(keyconf);
03625 }
03626