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