2.5
[blender-staging.git] / source / blender / editors / screen / screen_ops.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 #include <math.h>
28
29 #include "MEM_guardedalloc.h"
30
31 #include "BLI_arithb.h"
32 #include "BLI_blenlib.h"
33 #include "BLI_editVert.h"
34
35 #include "DNA_armature_types.h"
36 #include "DNA_image_types.h"
37 #include "DNA_object_types.h"
38 #include "DNA_mesh_types.h"
39 #include "DNA_curve_types.h"
40 #include "DNA_scene_types.h"
41
42 #include "BKE_blender.h"
43 #include "BKE_context.h"
44 #include "BKE_customdata.h"
45 #include "BKE_global.h"
46 #include "BKE_image.h"
47 #include "BKE_idprop.h"
48 #include "BKE_library.h"
49 #include "BKE_main.h"
50 #include "BKE_mesh.h"
51 #include "BKE_multires.h"
52 #include "BKE_report.h"
53 #include "BKE_screen.h"
54 #include "BKE_utildefines.h"
55
56 #include "WM_api.h"
57 #include "WM_types.h"
58
59 #include "ED_util.h"
60 #include "ED_screen.h"
61 #include "ED_mesh.h"
62 #include "ED_screen_types.h"
63
64 #include "RE_pipeline.h"
65 #include "IMB_imbuf.h"
66 #include "IMB_imbuf_types.h"
67
68 #include "RNA_access.h"
69 #include "RNA_define.h"
70
71 #include "UI_interface.h"
72 #include "UI_resources.h"
73
74 #include "screen_intern.h"      /* own module include */
75
76 /* ************** Exported Poll tests ********************** */
77
78 int ED_operator_regionactive(bContext *C)
79 {
80         if(CTX_wm_window(C)==NULL) return 0;
81         if(CTX_wm_screen(C)==NULL) return 0;
82         if(CTX_wm_region(C)==NULL) return 0;
83         return 1;
84 }
85
86 int ED_operator_areaactive(bContext *C)
87 {
88         if(CTX_wm_window(C)==NULL) return 0;
89         if(CTX_wm_screen(C)==NULL) return 0;
90         if(CTX_wm_area(C)==NULL) return 0;
91         return 1;
92 }
93
94 int ED_operator_screenactive(bContext *C)
95 {
96         if(CTX_wm_window(C)==NULL) return 0;
97         if(CTX_wm_screen(C)==NULL) return 0;
98         return 1;
99 }
100
101 /* when mouse is over area-edge */
102 int ED_operator_screen_mainwinactive(bContext *C)
103 {
104         if(CTX_wm_window(C)==NULL) return 0;
105         if(CTX_wm_screen(C)==NULL) return 0;
106         if (CTX_wm_screen(C)->subwinactive!=CTX_wm_screen(C)->mainwin) return 0;
107         return 1;
108 }
109
110 int ED_operator_scene_editable(bContext *C)
111 {
112         Scene *scene= CTX_data_scene(C);
113         if(scene && scene->id.lib==NULL)
114                 return 1;
115         return 0;
116 }
117
118 static int ed_spacetype_test(bContext *C, int type)
119 {
120         if(ED_operator_areaactive(C)) {
121                 SpaceLink *sl= (SpaceLink *)CTX_wm_space_data(C);
122                 return sl && (sl->spacetype == type);
123         }
124         return 0;
125 }
126
127 int ED_operator_view3d_active(bContext *C)
128 {
129         return ed_spacetype_test(C, SPACE_VIEW3D);
130 }
131
132 int ED_operator_timeline_active(bContext *C)
133 {
134         return ed_spacetype_test(C, SPACE_TIME);
135 }
136
137 int ED_operator_outliner_active(bContext *C)
138 {
139         return ed_spacetype_test(C, SPACE_OUTLINER);
140 }
141
142 int ED_operator_file_active(bContext *C)
143 {
144         return ed_spacetype_test(C, SPACE_FILE);
145 }
146
147 int ED_operator_action_active(bContext *C)
148 {
149         return ed_spacetype_test(C, SPACE_ACTION);
150 }
151
152 int ED_operator_buttons_active(bContext *C)
153 {
154         return ed_spacetype_test(C, SPACE_BUTS);
155 }
156
157 int ED_operator_node_active(bContext *C)
158 {
159         if(ed_spacetype_test(C, SPACE_NODE)) {
160                 SpaceNode *snode= (SpaceNode *)CTX_wm_space_data(C);
161                 if(snode->edittree)
162                         return 1;
163         }
164         return 0;
165 }
166
167 int ED_operator_ipo_active(bContext *C)
168 {
169         return ed_spacetype_test(C, SPACE_IPO);
170 }
171
172 int ED_operator_sequencer_active(bContext *C)
173 {
174         return ed_spacetype_test(C, SPACE_SEQ);
175 }
176
177 int ED_operator_image_active(bContext *C)
178 {
179         return ed_spacetype_test(C, SPACE_IMAGE);
180 }
181
182 int ED_operator_object_active(bContext *C)
183 {
184         return NULL != CTX_data_active_object(C);
185 }
186
187 int ED_operator_editmesh(bContext *C)
188 {
189         Object *obedit= CTX_data_edit_object(C);
190         if(obedit && obedit->type==OB_MESH)
191                 return NULL != ((Mesh *)obedit->data)->edit_mesh;
192         return 0;
193 }
194
195 int ED_operator_editarmature(bContext *C)
196 {
197         Object *obedit= CTX_data_edit_object(C);
198         if(obedit && obedit->type==OB_ARMATURE)
199                 return NULL != ((bArmature *)obedit->data)->edbo;
200         return 0;
201 }
202
203 int ED_operator_posemode(bContext *C)
204 {
205         Object *obact= CTX_data_active_object(C);
206         Object *obedit= CTX_data_edit_object(C);
207         
208         if ((obact != obedit) && (obact) && (obact->type==OB_ARMATURE))
209                 return (obact->flag & OB_POSEMODE)!=0;
210                 
211         return 0;
212 }
213
214
215 int ED_operator_uvedit(bContext *C)
216 {
217         Object *obedit= CTX_data_edit_object(C);
218         EditMesh *em= NULL;
219
220         if(obedit && obedit->type==OB_MESH)
221                 em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
222
223         if(em && (em->faces.first) && (CustomData_has_layer(&em->fdata, CD_MTFACE))) {
224                 BKE_mesh_end_editmesh(obedit->data, em);
225                 return 1;
226         }
227
228         BKE_mesh_end_editmesh(obedit->data, em);
229         return 0;
230 }
231
232 int ED_operator_uvmap(bContext *C)
233 {
234         Object *obedit= CTX_data_edit_object(C);
235         EditMesh *em= NULL;
236
237         if(obedit && obedit->type==OB_MESH)
238                 em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
239
240         if(em && (em->faces.first)) {
241                 BKE_mesh_end_editmesh(obedit->data, em);
242                 return 1;
243         }
244
245         BKE_mesh_end_editmesh(obedit->data, em);
246         return 0;
247 }
248
249 int ED_operator_editsurfcurve(bContext *C)
250 {
251         Object *obedit= CTX_data_edit_object(C);
252         if(obedit && ELEM(obedit->type, OB_CURVE, OB_SURF))
253                 return NULL != ((Curve *)obedit->data)->editnurb;
254         return 0;
255 }
256
257
258 int ED_operator_editcurve(bContext *C)
259 {
260         Object *obedit= CTX_data_edit_object(C);
261         if(obedit && obedit->type==OB_CURVE)
262                 return NULL != ((Curve *)obedit->data)->editnurb;
263         return 0;
264 }
265
266 int ED_operator_editsurf(bContext *C)
267 {
268         Object *obedit= CTX_data_edit_object(C);
269         if(obedit && obedit->type==OB_SURF)
270                 return NULL != ((Curve *)obedit->data)->editnurb;
271         return 0;
272 }
273
274 int ED_operator_editfont(bContext *C)
275 {
276         Object *obedit= CTX_data_edit_object(C);
277         if(obedit && obedit->type==OB_FONT)
278                 return NULL != ((Curve *)obedit->data)->editfont;
279         return 0;
280 }
281
282 /* *************************** action zone operator ************************** */
283
284 /* operator state vars used:  
285         none
286
287 functions:
288
289         apply() set actionzone event
290
291         exit()  free customdata
292         
293 callbacks:
294
295         exec()  never used
296
297         invoke() check if in zone  
298                 add customdata, put mouseco and area in it
299                 add modal handler
300
301         modal() accept modal events while doing it
302                 call apply() with gesture info, active window, nonactive window
303                 call exit() and remove handler when LMB confirm
304
305 */
306
307 typedef struct sActionzoneData {
308         ScrArea *sa1, *sa2;
309         AZone *az;
310         int x, y, gesture_dir, modifier;
311 } sActionzoneData;
312
313 /* used by other operators too */
314 static ScrArea *screen_areahascursor(bScreen *scr, int x, int y)
315 {
316         ScrArea *sa= NULL;
317         sa= scr->areabase.first;
318         while(sa) {
319                 if(BLI_in_rcti(&sa->totrct, x, y)) break;
320                 sa= sa->next;
321         }
322         
323         return sa;
324 }
325
326 /* quick poll to save operators to be created and handled */
327 static int actionzone_area_poll(bContext *C)
328 {
329         wmWindow *win= CTX_wm_window(C);
330         ScrArea *sa= CTX_wm_area(C);
331         
332         if(sa && win) {
333                 AZone *az;
334                 int x= win->eventstate->x;
335                 int y= win->eventstate->y;
336                 
337                 for(az= sa->actionzones.first; az; az= az->next)
338                         if(BLI_in_rcti(&az->rect, x, y))
339                            return 1;
340         }       
341         return 0;
342 }
343
344 AZone *is_in_area_actionzone(ScrArea *sa, int x, int y)
345 {
346         AZone *az= NULL;
347         
348         for(az= sa->actionzones.first; az; az= az->next) {
349                 if(BLI_in_rcti(&az->rect, x, y)) {
350                         if(az->type == AZONE_AREA) {
351                                 if(IsPointInTri2DInts(az->x1, az->y1, az->x2, az->y2, x, y)) 
352                                         break;
353                         }
354                         else if(az->type == AZONE_REGION) {
355                                 float v1[2], v2[2], v3[2], pt[2];
356                                 
357                                 v1[0]= az->x1; v1[1]= az->y1;
358                                 v2[0]= az->x2; v2[1]= az->y2;
359                                 v3[0]= az->x3; v3[1]= az->y3;
360                                 pt[0]= x; pt[1]=y;
361
362                                 if(IsPointInTri2D(v1, v2, v3, pt)) 
363                                         break;
364                         }
365                 }
366         }
367         
368         return az;
369 }
370
371
372 static void actionzone_exit(bContext *C, wmOperator *op)
373 {
374         if(op->customdata)
375                 MEM_freeN(op->customdata);
376         op->customdata= NULL;
377 }
378
379 /* send EVT_ACTIONZONE event */
380 static void actionzone_apply(bContext *C, wmOperator *op, int type)
381 {
382         wmEvent event;
383         wmWindow *win= CTX_wm_window(C);
384         sActionzoneData *sad= op->customdata;
385         
386         sad->modifier= RNA_int_get(op->ptr, "modifier");
387         
388         event= *(win->eventstate);      /* XXX huh huh? make api call */
389         if(type==AZONE_AREA)
390                 event.type= EVT_ACTIONZONE_AREA;
391         else
392                 event.type= EVT_ACTIONZONE_REGION;
393         event.customdata= op->customdata;
394         event.customdatafree= TRUE;
395         op->customdata= NULL;
396         
397         wm_event_add(win, &event);
398 }
399
400 static int actionzone_invoke(bContext *C, wmOperator *op, wmEvent *event)
401 {
402         AZone *az= is_in_area_actionzone(CTX_wm_area(C), event->x, event->y);
403         sActionzoneData *sad;
404         
405         /* quick escape */
406         if(az==NULL)
407                 return OPERATOR_PASS_THROUGH;
408         
409         /* ok we do the actionzone */
410         sad= op->customdata= MEM_callocN(sizeof(sActionzoneData), "sActionzoneData");
411         sad->sa1= CTX_wm_area(C);
412         sad->az= az;
413         sad->x= event->x; sad->y= event->y;
414         
415         /* region azone directly reacts on mouse clicks */
416         if(sad->az->type==AZONE_REGION) {
417                 actionzone_apply(C, op, AZONE_REGION);
418                 actionzone_exit(C, op);
419                 return OPERATOR_FINISHED;
420         }
421         else {
422                 /* add modal handler */
423                 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
424                 
425                 return OPERATOR_RUNNING_MODAL;
426         }
427 }
428
429
430 static int actionzone_modal(bContext *C, wmOperator *op, wmEvent *event)
431 {
432         sActionzoneData *sad= op->customdata;
433         int deltax, deltay;
434         int mindelta= sad->az->type==AZONE_REGION?1:12;
435         
436         switch(event->type) {
437                 case MOUSEMOVE:
438                         /* calculate gesture direction */
439                         deltax= (event->x - sad->x);
440                         deltay= (event->y - sad->y);
441                         
442                         if(deltay > ABS(deltax))
443                                 sad->gesture_dir= 'n';
444                         else if(deltax > ABS(deltay))
445                                 sad->gesture_dir= 'e';
446                         else if(deltay < -ABS(deltax))
447                                 sad->gesture_dir= 's';
448                         else
449                                 sad->gesture_dir= 'w';
450                         
451                         /* gesture is large enough? */
452                         if(ABS(deltax) > mindelta || ABS(deltay) > mindelta) {
453                                 
454                                 /* second area, for join */
455                                 sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
456                                 /* apply sends event */
457                                 actionzone_apply(C, op, sad->az->type);
458                                 actionzone_exit(C, op);
459                                 
460                                 return OPERATOR_FINISHED;
461                         }
462                                 break;
463                 case ESCKEY:
464                         actionzone_exit(C, op);
465                         return OPERATOR_CANCELLED;
466                 case LEFTMOUSE:                         
467                         actionzone_exit(C, op);
468                         return OPERATOR_CANCELLED;
469
470         }
471         
472         return OPERATOR_RUNNING_MODAL;
473 }
474
475 void SCREEN_OT_actionzone(wmOperatorType *ot)
476 {
477         /* identifiers */
478         ot->name= "Handle area action zones";
479         ot->idname= "SCREEN_OT_actionzone";
480         
481         ot->invoke= actionzone_invoke;
482         ot->modal= actionzone_modal;
483         
484         ot->poll= actionzone_area_poll;
485         RNA_def_int(ot->srna, "modifier", 0, 0, 2, "modifier", "modifier state", 0, 2);
486 }
487
488 /* ************** swap area operator *********************************** */
489
490 /* operator state vars used:  
491                                         sa1             start area
492                                         sa2             area to swap with
493
494         functions:
495
496         init()   set custom data for operator, based on actionzone event custom data
497
498         cancel()        cancel the operator
499
500         exit()  cleanup, send notifier
501
502         callbacks:
503
504         invoke() gets called on shift+lmb drag in actionzone
505             call init(), add handler
506
507         modal()  accept modal events while doing it
508
509 */
510
511 typedef struct sAreaSwapData {
512         ScrArea *sa1, *sa2;
513 } sAreaSwapData;
514
515 static int area_swap_init(bContext *C, wmOperator *op, wmEvent *event)
516 {
517         sAreaSwapData *sd= NULL;
518         sActionzoneData *sad= event->customdata;
519
520         if(sad==NULL || sad->sa1==NULL)
521                                         return 0;
522         
523         sd= MEM_callocN(sizeof(sAreaSwapData), "sAreaSwapData");
524         sd->sa1= sad->sa1;
525         sd->sa2= sad->sa2;
526         op->customdata= sd;
527
528         return 1;
529 }
530
531
532 static void area_swap_exit(bContext *C, wmOperator *op)
533 {
534         if(op->customdata)
535                 MEM_freeN(op->customdata);
536         op->customdata= NULL;
537 }
538
539 static int area_swap_cancel(bContext *C, wmOperator *op)
540 {
541         area_swap_exit(C, op);
542         return OPERATOR_CANCELLED;
543 }
544
545 static int area_swap_invoke(bContext *C, wmOperator *op, wmEvent *event)
546 {
547
548         if(!area_swap_init(C, op, event))
549                 return OPERATOR_PASS_THROUGH;
550
551         /* add modal handler */
552         WM_cursor_modal(CTX_wm_window(C), BC_SWAPAREA_CURSOR);
553         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
554         
555         return OPERATOR_RUNNING_MODAL;
556
557 }
558
559 static int area_swap_modal(bContext *C, wmOperator *op, wmEvent *event)
560 {
561         sActionzoneData *sad= op->customdata;
562
563         switch(event->type) {
564                 case MOUSEMOVE:
565                         /* second area, for join */
566                         sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
567                         break;
568                 case LEFTMOUSE: /* release LMB */
569                         if(event->val==0) {
570                                 if(sad->sa1 == sad->sa2) {
571
572                                         return area_swap_cancel(C, op);
573                                 }
574                                 ED_area_swapspace(C, sad->sa1, sad->sa2);
575
576                                 area_swap_exit(C, op);
577
578                                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
579
580                                 return OPERATOR_FINISHED;
581                         }
582                         break;
583
584                 case ESCKEY:
585                         return area_swap_cancel(C, op);
586         }
587         return OPERATOR_RUNNING_MODAL;
588 }
589
590 static void SCREEN_OT_area_swap(wmOperatorType *ot)
591 {
592         ot->name= "Swap areas";
593         ot->idname= "SCREEN_OT_area_swap";
594
595         ot->invoke= area_swap_invoke;
596         ot->modal= area_swap_modal;
597         ot->poll= ED_operator_areaactive;
598 }
599
600 /* *********** Duplicate area as new window operator ****************** */
601
602 /* operator callback */
603 static int area_dupli_invoke(bContext *C, wmOperator *op, wmEvent *event)
604 {
605         wmWindow *newwin, *win;
606         bScreen *newsc, *sc;
607         ScrArea *sa;
608         rcti rect;
609         sActionzoneData *sad= event->customdata;
610
611         if(sad==NULL)
612                 return OPERATOR_PASS_THROUGH;
613         
614         win= CTX_wm_window(C);
615         sc= CTX_wm_screen(C);
616         sa= sad->sa1;
617
618         /*  poll() checks area context, but we don't accept full-area windows */
619         if(sc->full != SCREENNORMAL) {
620                 actionzone_exit(C, op);
621                 return OPERATOR_CANCELLED;
622         }
623         
624         /* adds window to WM */
625         rect= sa->totrct;
626         BLI_translate_rcti(&rect, win->posx, win->posy);
627         newwin= WM_window_open(C, &rect);
628         
629         /* allocs new screen and adds to newly created window, using window size */
630         newsc= screen_add(newwin, CTX_data_scene(C), sc->id.name+2);
631         newwin->screen= newsc;
632         
633         /* copy area to new screen */
634         area_copy_data((ScrArea *)newsc->areabase.first, sa, 0);
635         
636         /* screen, areas init */
637         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
638
639         actionzone_exit(C, op);
640         
641         return OPERATOR_FINISHED;
642 }
643
644 static void SCREEN_OT_area_dupli(wmOperatorType *ot)
645 {
646         ot->name= "Duplicate Area into New Window";
647         ot->idname= "SCREEN_OT_area_dupli";
648         
649         ot->invoke= area_dupli_invoke;
650         ot->poll= ED_operator_areaactive;
651 }
652
653
654 /* ************** move area edge operator *********************************** */
655
656 /* operator state vars used:  
657            x, y                         mouse coord near edge
658            delta            movement of edge
659
660         functions:
661
662         init()   set default property values, find edge based on mouse coords, test
663             if the edge can be moved, select edges, calculate min and max movement
664
665         apply() apply delta on selection
666
667         exit()  cleanup, send notifier
668
669         cancel() cancel moving
670
671         callbacks:
672
673         exec()   execute without any user interaction, based on properties
674             call init(), apply(), exit()
675
676         invoke() gets called on mouse click near edge
677             call init(), add handler
678
679         modal()  accept modal events while doing it
680                         call apply() with delta motion
681             call exit() and remove handler
682
683 */
684
685 typedef struct sAreaMoveData {
686         int bigger, smaller, origval;
687         char dir;
688 } sAreaMoveData;
689
690 /* helper call to move area-edge, sets limits */
691 static void area_move_set_limits(bScreen *sc, int dir, int *bigger, int *smaller)
692 {
693         ScrArea *sa;
694         
695         /* we check all areas and test for free space with MINSIZE */
696         *bigger= *smaller= 100000;
697         
698         for(sa= sc->areabase.first; sa; sa= sa->next) {
699                 if(dir=='h') {
700                         int y1= sa->v2->vec.y - sa->v1->vec.y-AREAMINY;
701                         
702                         /* if top or down edge selected, test height */
703                         if(sa->v1->flag && sa->v4->flag)
704                                 *bigger= MIN2(*bigger, y1);
705                         else if(sa->v2->flag && sa->v3->flag)
706                                 *smaller= MIN2(*smaller, y1);
707                 }
708                 else {
709                         int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
710                         
711                         /* if left or right edge selected, test width */
712                         if(sa->v1->flag && sa->v2->flag)
713                                 *bigger= MIN2(*bigger, x1);
714                         else if(sa->v3->flag && sa->v4->flag)
715                                 *smaller= MIN2(*smaller, x1);
716                 }
717         }
718 }
719
720 /* validate selection inside screen, set variables OK */
721 /* return 0: init failed */
722 static int area_move_init (bContext *C, wmOperator *op)
723 {
724         bScreen *sc= CTX_wm_screen(C);
725         ScrEdge *actedge;
726         sAreaMoveData *md;
727         int x, y;
728
729         /* required properties */
730         x= RNA_int_get(op->ptr, "x");
731         y= RNA_int_get(op->ptr, "y");
732
733         /* setup */
734         actedge= screen_find_active_scredge(sc, x, y);
735         if(actedge==NULL) return 0;
736
737         md= MEM_callocN(sizeof(sAreaMoveData), "sAreaMoveData");
738         op->customdata= md;
739
740         md->dir= scredge_is_horizontal(actedge)?'h':'v';
741         if(md->dir=='h') md->origval= actedge->v1->vec.y;
742         else md->origval= actedge->v1->vec.x;
743         
744         select_connected_scredge(sc, actedge);
745         /* now all vertices with 'flag==1' are the ones that can be moved. */
746
747         area_move_set_limits(sc, md->dir, &md->bigger, &md->smaller);
748         
749         return 1;
750 }
751
752 /* moves selected screen edge amount of delta, used by split & move */
753 static void area_move_apply_do(bContext *C, int origval, int delta, int dir, int bigger, int smaller)
754 {
755         wmWindow *win= CTX_wm_window(C);
756         bScreen *sc= CTX_wm_screen(C);
757         ScrVert *v1;
758         
759         delta= CLAMPIS(delta, -smaller, bigger);
760         
761         for (v1= sc->vertbase.first; v1; v1= v1->next) {
762                 if (v1->flag) {
763                         /* that way a nice AREAGRID  */
764                         if((dir=='v') && v1->vec.x>0 && v1->vec.x<win->sizex-1) {
765                                 v1->vec.x= origval + delta;
766                                 if(delta != bigger && delta != -smaller) v1->vec.x-= (v1->vec.x % AREAGRID);
767                         }
768                         if((dir=='h') && v1->vec.y>0 && v1->vec.y<win->sizey-1) {
769                                 v1->vec.y= origval + delta;
770
771                                 v1->vec.y+= AREAGRID-1;
772                                 v1->vec.y-= (v1->vec.y % AREAGRID);
773                                 
774                                 /* prevent too small top header */
775                                 if(v1->vec.y > win->sizey-AREAMINY)
776                                         v1->vec.y= win->sizey-AREAMINY;
777                         }
778                 }
779         }
780
781         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
782 }
783
784 static void area_move_apply(bContext *C, wmOperator *op)
785 {
786         sAreaMoveData *md= op->customdata;
787         int delta;
788         
789         delta= RNA_int_get(op->ptr, "delta");
790         area_move_apply_do(C, md->origval, delta, md->dir, md->bigger, md->smaller);
791 }
792
793 static void area_move_exit(bContext *C, wmOperator *op)
794 {
795         if(op->customdata)
796                 MEM_freeN(op->customdata);
797         op->customdata= NULL;
798         
799         /* this makes sure aligned edges will result in aligned grabbing */
800         removedouble_scrverts(CTX_wm_screen(C));
801         removedouble_scredges(CTX_wm_screen(C));
802 }
803
804 static int area_move_exec(bContext *C, wmOperator *op)
805 {
806         if(!area_move_init(C, op))
807                 return OPERATOR_CANCELLED;
808         
809         area_move_apply(C, op);
810         area_move_exit(C, op);
811         
812         return OPERATOR_FINISHED;
813 }
814
815 /* interaction callback */
816 static int area_move_invoke(bContext *C, wmOperator *op, wmEvent *event)
817 {
818         RNA_int_set(op->ptr, "x", event->x);
819         RNA_int_set(op->ptr, "y", event->y);
820
821         if(!area_move_init(C, op)) 
822                 return OPERATOR_PASS_THROUGH;
823         
824         /* add temp handler */
825         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
826         
827         return OPERATOR_RUNNING_MODAL;
828 }
829
830 static int area_move_cancel(bContext *C, wmOperator *op)
831 {
832
833         RNA_int_set(op->ptr, "delta", 0);
834         area_move_apply(C, op);
835         area_move_exit(C, op);
836
837         return OPERATOR_CANCELLED;
838 }
839
840 /* modal callback for while moving edges */
841 static int area_move_modal(bContext *C, wmOperator *op, wmEvent *event)
842 {
843         sAreaMoveData *md;
844         int delta, x, y;
845
846         md= op->customdata;
847
848         x= RNA_int_get(op->ptr, "x");
849         y= RNA_int_get(op->ptr, "y");
850
851         /* execute the events */
852         switch(event->type) {
853                 case MOUSEMOVE:
854                         delta= (md->dir == 'v')? event->x - x: event->y - y;
855                         RNA_int_set(op->ptr, "delta", delta);
856
857                         area_move_apply(C, op);
858                         break;
859                         
860                 case LEFTMOUSE:
861                         if(event->val==0) {
862                                 area_move_exit(C, op);
863                                 return OPERATOR_FINISHED;
864                         }
865                         break;
866                         
867                 case ESCKEY:
868                         return area_move_cancel(C, op);
869         }
870         
871         return OPERATOR_RUNNING_MODAL;
872 }
873
874 void SCREEN_OT_area_move(wmOperatorType *ot)
875 {
876         /* identifiers */
877         ot->name= "Move area edges";
878         ot->idname= "SCREEN_OT_area_move";
879
880         ot->exec= area_move_exec;
881         ot->invoke= area_move_invoke;
882         ot->cancel= area_move_cancel;
883         ot->modal= area_move_modal;
884
885         ot->poll= ED_operator_screen_mainwinactive; /* when mouse is over area-edge */
886
887         /* rna */
888         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
889         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
890         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
891 }
892
893 /* ************** split area operator *********************************** */
894
895 /* 
896 operator state vars:  
897         fac              spit point
898         dir              direction 'v' or 'h'
899
900 operator customdata:
901         area                    pointer to (active) area
902         x, y                    last used mouse pos
903         (more, see below)
904
905 functions:
906
907         init()   set default property values, find area based on context
908
909         apply() split area based on state vars
910
911         exit()  cleanup, send notifier
912
913         cancel() remove duplicated area
914
915 callbacks:
916
917         exec()   execute without any user interaction, based on state vars
918             call init(), apply(), exit()
919
920         invoke() gets called on mouse click in action-widget
921             call init(), add modal handler
922                         call apply() with initial motion
923
924         modal()  accept modal events while doing it
925             call move-areas code with delta motion
926             call exit() or cancel() and remove handler
927
928 */
929
930 #define SPLIT_STARTED   1
931 #define SPLIT_PROGRESS  2
932
933 typedef struct sAreaSplitData
934 {
935         int x, y;       /* last used mouse position */
936         
937         int origval;                    /* for move areas */
938         int bigger, smaller;    /* constraints for moving new edge */
939         int delta;                              /* delta move edge */
940         int origmin, origsize;  /* to calculate fac, for property storage */
941
942         ScrEdge *nedge;                 /* new edge */
943         ScrArea *sarea;                 /* start area */
944         ScrArea *narea;                 /* new area */
945 } sAreaSplitData;
946
947 /* generic init, no UI stuff here */
948 static int area_split_init(bContext *C, wmOperator *op)
949 {
950         ScrArea *sa= CTX_wm_area(C);
951         sAreaSplitData *sd;
952         int dir;
953         
954         /* required context */
955         if(sa==NULL) return 0;
956         
957         /* required properties */
958         dir= RNA_enum_get(op->ptr, "direction");
959         
960         /* minimal size */
961         if(dir=='v' && sa->winx < 2*AREAMINX) return 0;
962         if(dir=='h' && sa->winy < 2*AREAMINY) return 0;
963            
964         /* custom data */
965         sd= (sAreaSplitData*)MEM_callocN(sizeof (sAreaSplitData), "op_area_split");
966         op->customdata= sd;
967         
968         sd->sarea= sa;
969         sd->origsize= dir=='v' ? sa->winx:sa->winy;
970         sd->origmin = dir=='v' ? sa->totrct.xmin:sa->totrct.ymin;
971         
972         return 1;
973 }
974
975 /* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
976 /* used with split operator */
977 static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *sa, ScrArea *sb)
978 {
979         ScrVert *sav1= sa->v1;
980         ScrVert *sav2= sa->v2;
981         ScrVert *sav3= sa->v3;
982         ScrVert *sav4= sa->v4;
983         ScrVert *sbv1= sb->v1;
984         ScrVert *sbv2= sb->v2;
985         ScrVert *sbv3= sb->v3;
986         ScrVert *sbv4= sb->v4;
987         
988         if(sav1==sbv4 && sav2==sbv3) { /* sa to right of sb = W */
989                 return screen_findedge(screen, sav1, sav2);
990         }
991         else if(sav2==sbv1 && sav3==sbv4) { /* sa to bottom of sb = N */
992                 return screen_findedge(screen, sav2, sav3);
993         }
994         else if(sav3==sbv2 && sav4==sbv1) { /* sa to left of sb = E */
995                 return screen_findedge(screen, sav3, sav4);
996         }
997         else if(sav1==sbv2 && sav4==sbv3) { /* sa on top of sb = S*/
998                 return screen_findedge(screen, sav1, sav4);
999         }
1000
1001         return NULL;
1002 }
1003
1004
1005 /* do the split, return success */
1006 static int area_split_apply(bContext *C, wmOperator *op)
1007 {
1008         bScreen *sc= CTX_wm_screen(C);
1009         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1010         float fac;
1011         int dir;
1012         
1013         fac= RNA_float_get(op->ptr, "factor");
1014         dir= RNA_enum_get(op->ptr, "direction");
1015
1016         sd->narea= area_split(CTX_wm_window(C), sc, sd->sarea, dir, fac);
1017         
1018         if(sd->narea) {
1019                 ScrVert *sv;
1020                 
1021                 sd->nedge= area_findsharededge(sc, sd->sarea, sd->narea);
1022         
1023                 /* select newly created edge, prepare for moving edge */
1024                 for(sv= sc->vertbase.first; sv; sv= sv->next)
1025                         sv->flag = 0;
1026                 
1027                 sd->nedge->v1->flag= 1;
1028                 sd->nedge->v2->flag= 1;
1029
1030                 if(dir=='h') sd->origval= sd->nedge->v1->vec.y;
1031                 else sd->origval= sd->nedge->v1->vec.x;
1032
1033                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1034                 
1035                 return 1;
1036         }               
1037         
1038         return 0;
1039 }
1040
1041 static void area_split_exit(bContext *C, wmOperator *op)
1042 {
1043         if (op->customdata) {
1044                 MEM_freeN(op->customdata);
1045                 op->customdata = NULL;
1046         }
1047         
1048         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1049
1050         /* this makes sure aligned edges will result in aligned grabbing */
1051         removedouble_scrverts(CTX_wm_screen(C));
1052         removedouble_scredges(CTX_wm_screen(C));
1053 }
1054
1055
1056 /* UI callback, adds new handler */
1057 static int area_split_invoke(bContext *C, wmOperator *op, wmEvent *event)
1058 {
1059         sAreaSplitData *sd;
1060         
1061         if(event->type==EVT_ACTIONZONE_AREA) {
1062                 sActionzoneData *sad= event->customdata;
1063                 int dir;
1064
1065                 if(sad->modifier>0) {
1066                         return OPERATOR_PASS_THROUGH;
1067                 }
1068                 
1069                 /* no full window splitting allowed */
1070                 if(CTX_wm_area(C)->full)
1071                         return OPERATOR_PASS_THROUGH;
1072                 
1073                 /* verify *sad itself */
1074                 if(sad==NULL || sad->sa1==NULL || sad->az==NULL)
1075                         return OPERATOR_PASS_THROUGH;
1076                 
1077                 /* is this our *sad? if areas not equal it should be passed on */
1078                 if(CTX_wm_area(C)!=sad->sa1 || sad->sa1!=sad->sa2)
1079                         return OPERATOR_PASS_THROUGH;
1080                 
1081                 /* prepare operator state vars */
1082                 if(sad->gesture_dir=='n' || sad->gesture_dir=='s') {
1083                         dir= 'h';
1084                         RNA_float_set(op->ptr, "factor", ((float)(event->x - sad->sa1->v1->vec.x)) / (float)sad->sa1->winx);
1085                 }
1086                 else {
1087                         dir= 'v';
1088                         RNA_float_set(op->ptr, "factor", ((float)(event->y - sad->sa1->v1->vec.y)) / (float)sad->sa1->winy);
1089                 }
1090                 RNA_enum_set(op->ptr, "direction", dir);
1091
1092                 /* general init, also non-UI case, adds customdata, sets area and defaults */
1093                 if(!area_split_init(C, op))
1094                         return OPERATOR_PASS_THROUGH;
1095                 
1096                 sd= (sAreaSplitData *)op->customdata;
1097                 
1098                 sd->x= event->x;
1099                 sd->y= event->y;
1100                 
1101                 /* do the split */
1102                 if(area_split_apply(C, op)) {
1103                         area_move_set_limits(CTX_wm_screen(C), dir, &sd->bigger, &sd->smaller);
1104                         
1105                         /* add temp handler for edge move or cancel */
1106                         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1107                         
1108                         return OPERATOR_RUNNING_MODAL;
1109                 }
1110                 
1111         }
1112         else {
1113                 /* nonmodal for now */
1114                 return op->type->exec(C, op);
1115         }
1116         
1117         return OPERATOR_PASS_THROUGH;
1118 }
1119
1120 /* function to be called outside UI context, or for redo */
1121 static int area_split_exec(bContext *C, wmOperator *op)
1122 {
1123         
1124         if(!area_split_init(C, op))
1125                 return OPERATOR_CANCELLED;
1126         
1127         area_split_apply(C, op);
1128         area_split_exit(C, op);
1129         
1130         return OPERATOR_FINISHED;
1131 }
1132
1133
1134 static int area_split_cancel(bContext *C, wmOperator *op)
1135 {
1136         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1137
1138         if (screen_area_join(C, CTX_wm_screen(C), sd->sarea, sd->narea)) {
1139                 if (CTX_wm_area(C) == sd->narea) {
1140                         CTX_wm_area_set(C, NULL);
1141                         CTX_wm_region_set(C, NULL);
1142                 }
1143                 sd->narea = NULL;
1144         }
1145         area_split_exit(C, op);
1146
1147         return OPERATOR_CANCELLED;
1148 }
1149
1150 static int area_split_modal(bContext *C, wmOperator *op, wmEvent *event)
1151 {
1152         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1153         float fac;
1154         int dir;
1155
1156         /* execute the events */
1157         switch(event->type) {
1158                 case MOUSEMOVE:
1159                         dir= RNA_enum_get(op->ptr, "direction");
1160                         
1161                         sd->delta= (dir == 'v')? event->x - sd->origval: event->y - sd->origval;
1162                         area_move_apply_do(C, sd->origval, sd->delta, dir, sd->bigger, sd->smaller);
1163                         
1164                         fac= (dir == 'v') ? event->x-sd->origmin : event->y-sd->origmin;
1165                         RNA_float_set(op->ptr, "factor", fac / (float)sd->origsize);
1166                         
1167                         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1168                         break;
1169                         
1170                 case LEFTMOUSE:
1171                         if(event->val==0) { /* mouse up */
1172                                 area_split_exit(C, op);
1173                                 return OPERATOR_FINISHED;
1174                         }
1175                         break;
1176                 case RIGHTMOUSE: /* cancel operation */
1177                 case ESCKEY:
1178                         return area_split_cancel(C, op);
1179         }
1180         
1181         return OPERATOR_RUNNING_MODAL;
1182 }
1183
1184 static EnumPropertyItem prop_direction_items[] = {
1185         {'h', "HORIZONTAL", "Horizontal", ""},
1186         {'v', "VERTICAL", "Vertical", ""},
1187         {0, NULL, NULL, NULL}};
1188
1189 void SCREEN_OT_area_split(wmOperatorType *ot)
1190 {
1191         ot->name = "Split area";
1192         ot->idname = "SCREEN_OT_area_split";
1193         
1194         ot->exec= area_split_exec;
1195         ot->invoke= area_split_invoke;
1196         ot->modal= area_split_modal;
1197         
1198         ot->poll= ED_operator_areaactive;
1199         ot->flag= OPTYPE_REGISTER;
1200         
1201         /* rna */
1202         RNA_def_enum(ot->srna, "direction", prop_direction_items, 'h', "Direction", "");
1203         RNA_def_float(ot->srna, "factor", 0.5f, 0.0, 1.0, "Factor", "", 0.0, 1.0);
1204 }
1205
1206
1207
1208 /* ************** scale region edge operator *********************************** */
1209
1210 typedef struct RegionMoveData {
1211         ARegion *ar;
1212         int bigger, smaller, origval;
1213         int origx, origy;
1214         char edge;
1215         
1216 } RegionMoveData;
1217
1218 static int region_scale_invoke(bContext *C, wmOperator *op, wmEvent *event)
1219 {
1220         sActionzoneData *sad= event->customdata;
1221         AZone *az= sad->az;
1222         
1223         if(az->ar) {
1224                 RegionMoveData *rmd= MEM_callocN(sizeof(RegionMoveData), "RegionMoveData");
1225                 
1226                 op->customdata= rmd;
1227                 
1228                 rmd->ar= az->ar;
1229                 rmd->edge= az->edge;
1230                 rmd->origx= event->x;
1231                 rmd->origy= event->y;
1232                 if(rmd->edge=='l' || rmd->edge=='r') 
1233                         rmd->origval= rmd->ar->type->minsizex;
1234                 else
1235                         rmd->origval= rmd->ar->type->minsizey;
1236                 
1237                 /* add temp handler */
1238                 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1239                 
1240                 return OPERATOR_RUNNING_MODAL;
1241         }
1242         
1243         return OPERATOR_FINISHED;
1244 }
1245
1246 static int region_scale_modal(bContext *C, wmOperator *op, wmEvent *event)
1247 {
1248         RegionMoveData *rmd= op->customdata;
1249         int delta;
1250         
1251         /* execute the events */
1252         switch(event->type) {
1253                 case MOUSEMOVE:
1254                         
1255                         if(rmd->edge=='l' || rmd->edge=='r') {
1256                                 delta= event->x - rmd->origx;
1257                                 if(rmd->edge=='l') delta= -delta;
1258                                 rmd->ar->type->minsizex= rmd->origval + delta;
1259                                 CLAMP(rmd->ar->type->minsizex, 0, 1000);
1260                                 if(rmd->ar->type->minsizex < 10) {
1261                                         rmd->ar->type->minsizex= 10;
1262                                         rmd->ar->flag |= RGN_FLAG_HIDDEN;
1263                                 }
1264                                 else
1265                                         rmd->ar->flag &= ~RGN_FLAG_HIDDEN;
1266                         }
1267                         else {
1268                                 delta= event->y - rmd->origy;
1269                                 if(rmd->edge=='b') delta= -delta;
1270                                 rmd->ar->type->minsizey= rmd->origval + delta;
1271                                 CLAMP(rmd->ar->type->minsizey, 0, 1000);
1272                                 if(rmd->ar->type->minsizey < 10) {
1273                                         rmd->ar->type->minsizey= 10;
1274                                         rmd->ar->flag |= RGN_FLAG_HIDDEN;
1275                                 }
1276                                 else
1277                                         rmd->ar->flag &= ~RGN_FLAG_HIDDEN;
1278                         }
1279                         
1280                         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1281                                         
1282                         break;
1283                         
1284                 case LEFTMOUSE:
1285                         if(event->val==0) {
1286                                 
1287                                 if(ABS(event->x - rmd->origx) < 2 && ABS(event->y - rmd->origy) < 2) {
1288                                         rmd->ar->flag ^= RGN_FLAG_HIDDEN;
1289                                         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1290                                 }                               
1291                                 MEM_freeN(op->customdata);
1292                                 op->customdata = NULL;
1293
1294                                 return OPERATOR_FINISHED;
1295                         }
1296                         break;
1297                         
1298                 case ESCKEY:
1299                         ;
1300         }
1301         
1302         return OPERATOR_RUNNING_MODAL;
1303 }
1304
1305
1306 static void SCREEN_OT_region_scale(wmOperatorType *ot)
1307 {
1308         /* identifiers */
1309         ot->name= "Scale Region Size";
1310         ot->idname= "SCREEN_OT_region_scale";
1311         
1312         ot->invoke= region_scale_invoke;
1313         ot->modal= region_scale_modal;
1314         
1315         ot->poll= ED_operator_areaactive;
1316 }
1317
1318
1319 /* ************** frame change operator ***************************** */
1320
1321
1322 /* function to be called outside UI context, or for redo */
1323 static int frame_offset_exec(bContext *C, wmOperator *op)
1324 {
1325         int delta;
1326
1327         delta = RNA_int_get(op->ptr, "delta");
1328
1329         CTX_data_scene(C)->r.cfra += delta;
1330
1331         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
1332
1333         return OPERATOR_FINISHED;
1334 }
1335
1336 void SCREEN_OT_frame_offset(wmOperatorType *ot)
1337 {
1338         ot->name = "Frame Offset";
1339         ot->idname = "SCREEN_OT_frame_offset";
1340
1341         ot->exec= frame_offset_exec;
1342
1343         ot->poll= ED_operator_screenactive;
1344         ot->flag= 0;
1345
1346         /* rna */
1347         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1348 }
1349
1350 /* ************** switch screen operator ***************************** */
1351
1352
1353 /* function to be called outside UI context, or for redo */
1354 static int screen_set_exec(bContext *C, wmOperator *op)
1355 {
1356         bScreen *screen= CTX_wm_screen(C);
1357         ScrArea *sa= CTX_wm_area(C);
1358         int tot= BLI_countlist(&CTX_data_main(C)->screen);
1359         int delta= RNA_int_get(op->ptr, "delta");
1360         
1361         /* this screen is 'fake', solve later XXX */
1362         if(sa && sa->full)
1363                 return OPERATOR_CANCELLED;
1364         
1365         if(delta==1) {
1366                 while(tot--) {
1367                         screen= screen->id.next;
1368                         if(screen==NULL) screen= CTX_data_main(C)->screen.first;
1369                         if(screen->winid==0 && screen->full==0)
1370                                 break;
1371                 }
1372         }
1373         else if(delta== -1) {
1374                 while(tot--) {
1375                         screen= screen->id.prev;
1376                         if(screen==NULL) screen= CTX_data_main(C)->screen.last;
1377                         if(screen->winid==0 && screen->full==0)
1378                                 break;
1379                 }
1380         }
1381         else {
1382                 screen= NULL;
1383         }
1384         
1385         if(screen) {
1386                 ED_screen_set(C, screen);
1387                 return OPERATOR_FINISHED;
1388         }
1389         return OPERATOR_CANCELLED;
1390 }
1391
1392 void SCREEN_OT_screen_set(wmOperatorType *ot)
1393 {
1394         ot->name = "Set Screen";
1395         ot->idname = "SCREEN_OT_screen_set";
1396         
1397         ot->exec= screen_set_exec;
1398         ot->poll= ED_operator_screenactive;
1399         
1400         /* rna */
1401         RNA_def_pointer_runtime(ot->srna, "screen", &RNA_Screen, "Screen", "");
1402         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1403 }
1404
1405 /* ************** screen full-area operator ***************************** */
1406
1407
1408 /* function to be called outside UI context, or for redo */
1409 static int screen_full_area_exec(bContext *C, wmOperator *op)
1410 {
1411         ed_screen_fullarea(C, CTX_wm_area(C));
1412         return OPERATOR_FINISHED;
1413 }
1414
1415 void SCREEN_OT_screen_full_area(wmOperatorType *ot)
1416 {
1417         ot->name = "Toggle Make Area Fullscreen";
1418         ot->idname = "SCREEN_OT_screen_full_area";
1419         
1420         ot->exec= screen_full_area_exec;
1421         ot->poll= ED_operator_areaactive;
1422         ot->flag= 0;
1423
1424 }
1425
1426
1427
1428 /* ************** join area operator ********************************************** */
1429
1430 /* operator state vars used:  
1431                         x1, y1     mouse coord in first area, which will disappear
1432                         x2, y2     mouse coord in 2nd area, which will become joined
1433
1434 functions:
1435
1436    init()   find edge based on state vars 
1437                         test if the edge divides two areas, 
1438                         store active and nonactive area,
1439             
1440    apply()  do the actual join
1441
1442    exit()       cleanup, send notifier
1443
1444 callbacks:
1445
1446    exec()       calls init, apply, exit 
1447    
1448    invoke() sets mouse coords in x,y
1449             call init()
1450             add modal handler
1451
1452    modal()      accept modal events while doing it
1453                         call apply() with active window and nonactive window
1454             call exit() and remove handler when LMB confirm
1455
1456 */
1457
1458 typedef struct sAreaJoinData
1459 {
1460         ScrArea *sa1;   /* first area to be considered */
1461         ScrArea *sa2;   /* second area to be considered */
1462         ScrArea *scr;   /* designed for removal */
1463
1464 } sAreaJoinData;
1465
1466
1467 /* validate selection inside screen, set variables OK */
1468 /* return 0: init failed */
1469 /* XXX todo: find edge based on (x,y) and set other area? */
1470 static int area_join_init(bContext *C, wmOperator *op)
1471 {
1472         ScrArea *sa1, *sa2;
1473         sAreaJoinData* jd= NULL;
1474         int x1, y1;
1475         int x2, y2;
1476
1477         /* required properties, make negative to get return 0 if not set by caller */
1478         x1= RNA_int_get(op->ptr, "x1");
1479         y1= RNA_int_get(op->ptr, "y1");
1480         x2= RNA_int_get(op->ptr, "x2");
1481         y2= RNA_int_get(op->ptr, "y2");
1482         
1483         sa1 = screen_areahascursor(CTX_wm_screen(C), x1, y1);
1484         sa2 = screen_areahascursor(CTX_wm_screen(C), x2, y2);
1485         if(sa1==NULL || sa2==NULL || sa1==sa2)
1486                 return 0;
1487
1488         jd = (sAreaJoinData*)MEM_callocN(sizeof (sAreaJoinData), "op_area_join");
1489                 
1490         jd->sa1 = sa1;
1491         jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1492         jd->sa2 = sa2;
1493         jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1494         
1495         op->customdata= jd;
1496         
1497         return 1;
1498 }
1499
1500 /* apply the join of the areas (space types) */
1501 static int area_join_apply(bContext *C, wmOperator *op)
1502 {
1503         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1504         if (!jd) return 0;
1505
1506         if(!screen_area_join(C, CTX_wm_screen(C), jd->sa1, jd->sa2)){
1507                 return 0;
1508         }
1509         if (CTX_wm_area(C) == jd->sa2) {
1510                 CTX_wm_area_set(C, NULL);
1511                 CTX_wm_region_set(C, NULL);
1512         }
1513
1514         return 1;
1515 }
1516
1517 /* finish operation */
1518 static void area_join_exit(bContext *C, wmOperator *op)
1519 {
1520         if (op->customdata) {
1521                 MEM_freeN(op->customdata);
1522                 op->customdata = NULL;
1523         }
1524
1525         /* this makes sure aligned edges will result in aligned grabbing */
1526         removedouble_scredges(CTX_wm_screen(C));
1527         removenotused_scredges(CTX_wm_screen(C));
1528         removenotused_scrverts(CTX_wm_screen(C));
1529 }
1530
1531 static int area_join_exec(bContext *C, wmOperator *op)
1532 {
1533         if(!area_join_init(C, op)) 
1534                 return OPERATOR_CANCELLED;
1535         
1536         area_join_apply(C, op);
1537         area_join_exit(C, op);
1538
1539         return OPERATOR_FINISHED;
1540 }
1541
1542 /* interaction callback */
1543 static int area_join_invoke(bContext *C, wmOperator *op, wmEvent *event)
1544 {
1545
1546         if(event->type==EVT_ACTIONZONE_AREA) {
1547                 sActionzoneData *sad= event->customdata;
1548
1549                 if(sad->modifier>0) {
1550                         return OPERATOR_PASS_THROUGH;
1551                 }
1552                 
1553                 /* verify *sad itself */
1554                 if(sad==NULL || sad->sa1==NULL || sad->sa2==NULL)
1555                         return OPERATOR_PASS_THROUGH;
1556                 
1557                 /* is this our *sad? if areas equal it should be passed on */
1558                 if(sad->sa1==sad->sa2)
1559                         return OPERATOR_PASS_THROUGH;
1560                 
1561                 /* prepare operator state vars */
1562                 RNA_int_set(op->ptr, "x1", sad->x);
1563                 RNA_int_set(op->ptr, "y1", sad->y);
1564                 RNA_int_set(op->ptr, "x2", event->x);
1565                 RNA_int_set(op->ptr, "y2", event->y);
1566
1567                 if(!area_join_init(C, op)) 
1568                         return OPERATOR_PASS_THROUGH;
1569         
1570                 /* add temp handler */
1571                 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1572         
1573                 return OPERATOR_RUNNING_MODAL;
1574         }
1575         
1576         return OPERATOR_PASS_THROUGH;
1577 }
1578
1579 static int area_join_cancel(bContext *C, wmOperator *op)
1580 {
1581         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1582
1583         if (jd->sa1) {
1584                 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1585                 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINTO;
1586         }
1587         if (jd->sa2) {
1588                 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINFROM;
1589                 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1590         }
1591
1592         WM_event_add_notifier(C, NC_WINDOW, NULL);
1593         
1594         area_join_exit(C, op);
1595
1596         return OPERATOR_CANCELLED;
1597 }
1598
1599 /* modal callback while selecting area (space) that will be removed */
1600 static int area_join_modal(bContext *C, wmOperator *op, wmEvent *event)
1601 {
1602         bScreen *sc= CTX_wm_screen(C);
1603         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1604         
1605         /* execute the events */
1606         switch(event->type) {
1607                         
1608                 case MOUSEMOVE: 
1609                         {
1610                                 ScrArea *sa = screen_areahascursor(sc, event->x, event->y);
1611                                 int dir;
1612                                 
1613                                 if (sa) {                                       
1614                                         if (jd->sa1 != sa) {
1615                                                 dir = area_getorientation(sc, jd->sa1, sa);
1616                                                 if (dir >= 0) {
1617                                                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1618                                                         jd->sa2 = sa;
1619                                                         jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1620                                                 } 
1621                                                 else {
1622                                                         /* we are not bordering on the previously selected area 
1623                                                            we check if area has common border with the one marked for removal
1624                                                            in this case we can swap areas.
1625                                                         */
1626                                                         dir = area_getorientation(sc, sa, jd->sa2);
1627                                                         if (dir >= 0) {
1628                                                                 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1629                                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1630                                                                 jd->sa1 = jd->sa2;
1631                                                                 jd->sa2 = sa;
1632                                                                 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1633                                                                 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1634                                                         } 
1635                                                         else {
1636                                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1637                                                                 jd->sa2 = NULL;
1638                                                         }
1639                                                 }
1640                                                 WM_event_add_notifier(C, NC_WINDOW, NULL);
1641                                         } 
1642                                         else {
1643                                                 /* we are back in the area previously selected for keeping 
1644                                                  * we swap the areas if possible to allow user to choose */
1645                                                 if (jd->sa2 != NULL) {
1646                                                         if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1647                                                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1648                                                         jd->sa1 = jd->sa2;
1649                                                         jd->sa2 = sa;
1650                                                         if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1651                                                         if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1652                                                         dir = area_getorientation(sc, jd->sa1, jd->sa2);
1653                                                         if (dir < 0) {
1654                                                                 printf("oops, didn't expect that!\n");
1655                                                         }
1656                                                 } 
1657                                                 else {
1658                                                         dir = area_getorientation(sc, jd->sa1, sa);
1659                                                         if (dir >= 0) {
1660                                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1661                                                                 jd->sa2 = sa;
1662                                                                 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1663                                                         }
1664                                                 }
1665                                                 WM_event_add_notifier(C, NC_WINDOW, NULL);
1666                                         }
1667                                 }
1668                         }
1669                         break;
1670                 case LEFTMOUSE:
1671                         if(event->val==0) {
1672                                 area_join_apply(C, op);
1673                                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1674                                 area_join_exit(C, op);
1675                                 return OPERATOR_FINISHED;
1676                         }
1677                         break;
1678                         
1679                 case ESCKEY:
1680                         return area_join_cancel(C, op);
1681         }
1682
1683         return OPERATOR_RUNNING_MODAL;
1684 }
1685
1686 /* Operator for joining two areas (space types) */
1687 void SCREEN_OT_area_join(wmOperatorType *ot)
1688 {
1689         /* identifiers */
1690         ot->name= "Join area";
1691         ot->idname= "SCREEN_OT_area_join";
1692         
1693         /* api callbacks */
1694         ot->exec= area_join_exec;
1695         ot->invoke= area_join_invoke;
1696         ot->modal= area_join_modal;
1697
1698         ot->poll= ED_operator_areaactive;
1699
1700         /* rna */
1701         RNA_def_int(ot->srna, "x1", -100, INT_MIN, INT_MAX, "X 1", "", INT_MIN, INT_MAX);
1702         RNA_def_int(ot->srna, "y1", -100, INT_MIN, INT_MAX, "Y 1", "", INT_MIN, INT_MAX);
1703         RNA_def_int(ot->srna, "x2", -100, INT_MIN, INT_MAX, "X 2", "", INT_MIN, INT_MAX);
1704         RNA_def_int(ot->srna, "y2", -100, INT_MIN, INT_MAX, "Y 2", "", INT_MIN, INT_MAX);
1705 }
1706
1707 /* ************** repeat last operator ***************************** */
1708
1709 static int repeat_last_exec(bContext *C, wmOperator *op)
1710 {
1711         wmOperator *lastop= CTX_wm_manager(C)->operators.last;
1712         
1713         if(lastop)
1714                 WM_operator_repeat(C, lastop);
1715         
1716         return OPERATOR_CANCELLED;
1717 }
1718
1719 void SCREEN_OT_repeat_last(wmOperatorType *ot)
1720 {
1721         /* identifiers */
1722         ot->name= "Repeat Last";
1723         ot->idname= "SCREEN_OT_repeat_last";
1724         
1725         /* api callbacks */
1726         ot->exec= repeat_last_exec;
1727         
1728         ot->poll= ED_operator_screenactive;
1729         
1730 }
1731
1732 static int repeat_history_invoke(bContext *C, wmOperator *op, wmEvent *event)
1733 {
1734         wmWindowManager *wm= CTX_wm_manager(C);
1735         wmOperator *lastop;
1736         uiPopupMenu *pup;
1737         uiLayout *layout;
1738         int items, i;
1739         
1740         items= BLI_countlist(&wm->operators);
1741         if(items==0)
1742                 return OPERATOR_CANCELLED;
1743         
1744         pup= uiPupMenuBegin(C, op->type->name, 0);
1745         layout= uiPupMenuLayout(pup);
1746
1747         for (i=items-1, lastop= wm->operators.last; lastop; lastop= lastop->prev, i--)
1748                 uiItemIntO(layout, lastop->type->name, 0, op->type->idname, "index", i);
1749
1750         uiPupMenuEnd(C, pup);
1751         
1752         return OPERATOR_CANCELLED;
1753 }
1754
1755 static int repeat_history_exec(bContext *C, wmOperator *op)
1756 {
1757         wmWindowManager *wm= CTX_wm_manager(C);
1758         
1759         op= BLI_findlink(&wm->operators, RNA_int_get(op->ptr, "index"));
1760         if(op) {
1761                 /* let's put it as last operator in list */
1762                 BLI_remlink(&wm->operators, op);
1763                 BLI_addtail(&wm->operators, op);
1764                 
1765                 WM_operator_repeat(C, op);
1766         }
1767                                          
1768         return OPERATOR_FINISHED;
1769 }
1770
1771 void SCREEN_OT_repeat_history(wmOperatorType *ot)
1772 {
1773         /* identifiers */
1774         ot->name= "Repeat History";
1775         ot->idname= "SCREEN_OT_repeat_history";
1776         
1777         /* api callbacks */
1778         ot->invoke= repeat_history_invoke;
1779         ot->exec= repeat_history_exec;
1780         
1781         ot->poll= ED_operator_screenactive;
1782         
1783         RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
1784 }
1785
1786 /* ********************** redo operator ***************************** */
1787
1788 static int redo_last_invoke(bContext *C, wmOperator *op, wmEvent *event)
1789 {
1790         wmWindowManager *wm= CTX_wm_manager(C);
1791         wmOperator *lastop;
1792
1793         /* only for operators that are registered and did an undo push */
1794         for(lastop= wm->operators.last; lastop; lastop= lastop->prev)
1795                 if((lastop->type->flag & OPTYPE_REGISTER) && (lastop->type->flag & OPTYPE_UNDO))
1796                         break;
1797         
1798         if(lastop)
1799                 WM_operator_redo_popup(C, lastop);
1800
1801         return OPERATOR_CANCELLED;
1802 }
1803
1804 void SCREEN_OT_redo_last(wmOperatorType *ot)
1805 {
1806         /* identifiers */
1807         ot->name= "Redo Last";
1808         ot->idname= "SCREEN_OT_redo_last";
1809         
1810         /* api callbacks */
1811         ot->invoke= redo_last_invoke;
1812         
1813         ot->poll= ED_operator_screenactive;
1814 }
1815
1816 /* ************** region split operator ***************************** */
1817
1818 /* insert a region in the area region list */
1819 static int region_split_exec(bContext *C, wmOperator *op)
1820 {
1821         ARegion *ar= CTX_wm_region(C);
1822         
1823         if(ar->regiontype==RGN_TYPE_HEADER)
1824                 BKE_report(op->reports, RPT_ERROR, "Cannot split header");
1825         else if(ar->alignment==RGN_ALIGN_QSPLIT)
1826                 BKE_report(op->reports, RPT_ERROR, "Cannot split further");
1827         else {
1828                 ScrArea *sa= CTX_wm_area(C);
1829                 ARegion *newar= BKE_area_region_copy(sa->type, ar);
1830                 int dir= RNA_enum_get(op->ptr, "type");
1831         
1832                 BLI_insertlinkafter(&sa->regionbase, ar, newar);
1833                 
1834                 newar->alignment= ar->alignment;
1835                 
1836                 if(dir=='h')
1837                         ar->alignment= RGN_ALIGN_HSPLIT;
1838                 else
1839                         ar->alignment= RGN_ALIGN_VSPLIT;
1840                 
1841                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1842         }
1843         
1844         return OPERATOR_FINISHED;
1845 }
1846
1847 void SCREEN_OT_region_split(wmOperatorType *ot)
1848 {
1849         /* identifiers */
1850         ot->name= "Split Region";
1851         ot->idname= "SCREEN_OT_region_split";
1852         
1853         /* api callbacks */
1854         ot->invoke= WM_menu_invoke;
1855         ot->exec= region_split_exec;
1856         ot->poll= ED_operator_areaactive;
1857         
1858         RNA_def_enum(ot->srna, "type", prop_direction_items, 'h', "Direction", "");
1859 }
1860
1861 /* ************** region four-split operator ***************************** */
1862
1863 /* insert a region in the area region list */
1864 static int region_foursplit_exec(bContext *C, wmOperator *op)
1865 {
1866         ARegion *ar= CTX_wm_region(C);
1867         
1868         /* some rules... */
1869         if(ar->regiontype!=RGN_TYPE_WINDOW)
1870                 BKE_report(op->reports, RPT_ERROR, "Only window region can be 4-splitted");
1871         else if(ar->alignment==RGN_ALIGN_QSPLIT) {
1872                 ScrArea *sa= CTX_wm_area(C);
1873                 ARegion *arn;
1874                 
1875                 /* keep current region */
1876                 ar->alignment= 0;
1877                 
1878                 if(sa->spacetype==SPACE_VIEW3D) {
1879                         RegionView3D *rv3d= ar->regiondata;
1880                         rv3d->viewlock= 0;
1881                         rv3d->rflag &= ~RV3D_CLIPPING;
1882                 }
1883                 
1884                 for(ar= sa->regionbase.first; ar; ar= arn) {
1885                         arn= ar->next;
1886                         if(ar->alignment==RGN_ALIGN_QSPLIT) {
1887                                 ED_region_exit(C, ar);
1888                                 BKE_area_region_free(sa->type, ar);
1889                                 BLI_remlink(&sa->regionbase, ar);
1890                                 MEM_freeN(ar);
1891                         }
1892                 }
1893                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1894         }
1895         else if(ar->next)
1896                 BKE_report(op->reports, RPT_ERROR, "Only last region can be 4-splitted");
1897         else {
1898                 ScrArea *sa= CTX_wm_area(C);
1899                 ARegion *newar;
1900                 int count;
1901                 
1902                 ar->alignment= RGN_ALIGN_QSPLIT;
1903                 
1904                 for(count=0; count<3; count++) {
1905                         newar= BKE_area_region_copy(sa->type, ar);
1906                         BLI_addtail(&sa->regionbase, newar);
1907                 }
1908                 
1909                 /* lock views and set them */
1910                 if(sa->spacetype==SPACE_VIEW3D) {
1911                         RegionView3D *rv3d;
1912                         
1913                         rv3d= ar->regiondata;
1914                         rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_FRONT; rv3d->persp= V3D_ORTHO;
1915                         
1916                         ar= ar->next;
1917                         rv3d= ar->regiondata;
1918                         rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_TOP; rv3d->persp= V3D_ORTHO;
1919                         
1920                         ar= ar->next;
1921                         rv3d= ar->regiondata;
1922                         rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_RIGHT; rv3d->persp= V3D_ORTHO;
1923                         
1924                         ar= ar->next;
1925                         rv3d= ar->regiondata;
1926                         rv3d->view= V3D_VIEW_CAMERA; rv3d->persp= V3D_CAMOB;
1927                 }
1928                 
1929                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1930         }
1931         
1932         
1933         return OPERATOR_FINISHED;
1934 }
1935
1936 void SCREEN_OT_region_foursplit(wmOperatorType *ot)
1937 {
1938         /* identifiers */
1939         ot->name= "Split Region in 4 Parts";
1940         ot->idname= "SCREEN_OT_region_foursplit";
1941         
1942         /* api callbacks */
1943         ot->invoke= WM_operator_confirm;
1944         ot->exec= region_foursplit_exec;
1945         ot->poll= ED_operator_areaactive;
1946         ot->flag= OPTYPE_REGISTER;
1947 }
1948
1949
1950
1951 /* ************** region flip operator ***************************** */
1952
1953 /* flip a region alignment */
1954 static int region_flip_exec(bContext *C, wmOperator *op)
1955 {
1956         ARegion *ar= CTX_wm_region(C);
1957
1958         if(ar->alignment==RGN_ALIGN_TOP)
1959                 ar->alignment= RGN_ALIGN_BOTTOM;
1960         else if(ar->alignment==RGN_ALIGN_BOTTOM)
1961                 ar->alignment= RGN_ALIGN_TOP;
1962         else if(ar->alignment==RGN_ALIGN_LEFT)
1963                 ar->alignment= RGN_ALIGN_RIGHT;
1964         else if(ar->alignment==RGN_ALIGN_RIGHT)
1965                 ar->alignment= RGN_ALIGN_LEFT;
1966         
1967         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1968         printf("executed region flip\n");
1969         
1970         return OPERATOR_FINISHED;
1971 }
1972
1973 static void testfunc(bContext *C, void *argv, int arg)
1974 {
1975         printf("arg %d\n", arg);
1976 }
1977
1978 static void newlevel1(bContext *C, uiLayout *layout, void *arg)
1979 {
1980         uiLayoutFunc(layout, testfunc, NULL);
1981         
1982         uiItemV(layout, "First", ICON_PROP_ON, 1);
1983         uiItemV(layout, "Second", ICON_PROP_CON, 2);
1984         uiItemV(layout, "Third", ICON_SMOOTHCURVE, 3);
1985         uiItemV(layout, "Fourth", ICON_SHARPCURVE, 4);  
1986 }
1987
1988 static int testing123(bContext *C, wmOperator *op, wmEvent *event)
1989 {
1990         uiPopupMenu *pup= uiPupMenuBegin(C, "Hello world", 0);
1991         uiLayout *layout= uiPupMenuLayout(pup);
1992         
1993         uiLayoutContext(layout, WM_OP_EXEC_DEFAULT);
1994         uiItemO(layout, NULL, ICON_PROP_ON, "SCREEN_OT_region_flip");
1995         uiItemO(layout, NULL, ICON_PROP_CON, "SCREEN_OT_screen_full_area");
1996         uiItemO(layout, NULL, ICON_SMOOTHCURVE, "SCREEN_OT_region_foursplit");
1997         uiItemMenuF(layout, "Submenu", 0, newlevel1);
1998         
1999         uiPupMenuEnd(C, pup);
2000         
2001         /* this operator is only for a menu, not used further */
2002         return OPERATOR_CANCELLED;
2003 }
2004
2005 void SCREEN_OT_region_flip(wmOperatorType *ot)
2006 {
2007         /* identifiers */
2008         ot->name= "Flip Region";
2009         ot->idname= "SCREEN_OT_region_flip";
2010         
2011         /* api callbacks */
2012         ot->invoke= testing123; // XXX WM_operator_confirm;
2013         ot->exec= region_flip_exec;
2014         
2015         ot->poll= ED_operator_areaactive;
2016         ot->flag= OPTYPE_REGISTER;
2017         
2018         RNA_def_int(ot->srna, "test", 0, INT_MIN, INT_MAX, "test", "", INT_MIN, INT_MAX);
2019
2020 }
2021
2022 /* ****************** anim player, with timer ***************** */
2023
2024 static int match_region_with_redraws(int spacetype, int regiontype, int redraws)
2025 {
2026         if(regiontype==RGN_TYPE_WINDOW) {
2027
2028                 switch (spacetype) {
2029                         case SPACE_VIEW3D:
2030                                 if(redraws & TIME_ALL_3D_WIN)
2031                                         return 1;
2032                                 break;
2033                         case SPACE_IPO:
2034                         case SPACE_ACTION:
2035                         case SPACE_NLA:
2036                                 if(redraws & TIME_ALL_ANIM_WIN)
2037                                         return 1;
2038                                 break;
2039                         case SPACE_TIME:
2040                                 /* if only 1 window or 3d windows, we do timeline too */
2041                                 if(redraws & (TIME_ALL_ANIM_WIN|TIME_REGION|TIME_ALL_3D_WIN))
2042                                         return 1;
2043                                 break;
2044                         case SPACE_BUTS:
2045                                 if(redraws & TIME_ALL_BUTS_WIN)
2046                                         return 1;
2047                                 break;
2048                         case SPACE_SEQ:
2049                                 if(redraws & (TIME_SEQ|TIME_ALL_ANIM_WIN))
2050                                         return 1;
2051                                 break;
2052                         case SPACE_IMAGE:
2053                                 if(redraws & TIME_ALL_IMAGE_WIN)
2054                                         return 1;
2055                                 break;
2056                                 
2057                 }
2058         }
2059         else if(regiontype==RGN_TYPE_UI) {
2060                 if(redraws & TIME_ALL_BUTS_WIN)
2061                         return 1;
2062         }
2063         else if(regiontype==RGN_TYPE_HEADER) {
2064                 if(spacetype==SPACE_TIME)
2065                         return 1;
2066         }
2067         return 0;
2068 }
2069
2070 static int screen_animation_step(bContext *C, wmOperator *op, wmEvent *event)
2071 {
2072         bScreen *screen= CTX_wm_screen(C);
2073         
2074         if(screen->animtimer==event->customdata) {
2075                 Scene *scene= CTX_data_scene(C);
2076                 wmTimer *wt= screen->animtimer;
2077                 ScreenAnimData *sad= wt->customdata;
2078                 ScrArea *sa;
2079                 
2080                 if(scene->audio.flag & AUDIO_SYNC) {
2081                         int step = floor(wt->duration * FPS);
2082                         scene->r.cfra += step;
2083                         wt->duration -= ((float)step)/FPS;
2084                 }
2085                 else
2086                         scene->r.cfra++;
2087                 
2088                 if (scene->r.psfra) {
2089                         if(scene->r.cfra > scene->r.pefra)
2090                                 scene->r.cfra= scene->r.psfra;
2091                 }
2092                 else {
2093                         if(scene->r.cfra > scene->r.efra)
2094                                 scene->r.cfra= scene->r.sfra;
2095                 }
2096
2097                 /* since we follow drawflags, we can't send notifier but tag regions ourselves */
2098                 ED_update_for_newframe(C, 1);
2099                 
2100                 for(sa= screen->areabase.first; sa; sa= sa->next) {
2101                         ARegion *ar;
2102                         for(ar= sa->regionbase.first; ar; ar= ar->next) {
2103                                 if(ar==sad->ar)
2104                                         ED_region_tag_redraw(ar);
2105                                 else
2106                                         if(match_region_with_redraws(sa->spacetype, ar->regiontype, sad->redraws))
2107                                                 ED_region_tag_redraw(ar);
2108                         }
2109                 }
2110                 
2111                 //WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
2112                 
2113                 return OPERATOR_FINISHED;
2114         }
2115         return OPERATOR_PASS_THROUGH;
2116 }
2117
2118 static void SCREEN_OT_animation_step(wmOperatorType *ot)
2119 {
2120         /* identifiers */
2121         ot->name= "Animation Step";
2122         ot->idname= "SCREEN_OT_animation_step";
2123         
2124         /* api callbacks */
2125         ot->invoke= screen_animation_step;
2126         
2127         ot->poll= ED_operator_screenactive;
2128         
2129 }
2130
2131 /* ****************** anim player, starts or ends timer ***************** */
2132
2133 /* toggle operator */
2134 static int screen_animation_play(bContext *C, wmOperator *op, wmEvent *event)
2135 {
2136         bScreen *screen= CTX_wm_screen(C);
2137         
2138         if(screen->animtimer) {
2139                 ED_screen_animation_timer(C, 0, 0);
2140         }
2141         else {
2142                 /* todo: RNA properties to define play types */
2143                 ED_screen_animation_timer(C, TIME_REGION|TIME_ALL_3D_WIN, 1);
2144                 
2145                 if(screen->animtimer) {
2146                         wmTimer *wt= screen->animtimer;
2147                         ScreenAnimData *sad= wt->customdata;
2148                         
2149                         sad->ar= CTX_wm_region(C);
2150                 }
2151         }
2152         
2153         return OPERATOR_FINISHED;
2154 }
2155
2156 void SCREEN_OT_animation_play(wmOperatorType *ot)
2157 {
2158         /* identifiers */
2159         ot->name= "Animation player";
2160         ot->idname= "SCREEN_OT_animation_play";
2161         
2162         /* api callbacks */
2163         ot->invoke= screen_animation_play;
2164         
2165         ot->poll= ED_operator_screenactive;
2166         
2167         
2168 }
2169
2170 /* ************** border select operator (template) ***************************** */
2171
2172 /* operator state vars used: (added by default WM callbacks)   
2173         xmin, ymin     
2174         xmax, ymax     
2175
2176         customdata: the wmGesture pointer
2177
2178 callbacks:
2179
2180         exec()  has to be filled in by user
2181
2182         invoke() default WM function
2183                          adds modal handler
2184
2185         modal() default WM function 
2186                         accept modal events while doing it, calls exec(), handles ESC and border drawing
2187         
2188         poll()  has to be filled in by user for context
2189 */
2190 #if 0
2191 static int border_select_do(bContext *C, wmOperator *op)
2192 {
2193         int event_type= RNA_int_get(op->ptr, "event_type");
2194         
2195         if(event_type==LEFTMOUSE)
2196                 printf("border select do select\n");
2197         else if(event_type==RIGHTMOUSE)
2198                 printf("border select deselect\n");
2199         else 
2200                 printf("border select do something\n");
2201         
2202         return 1;
2203 }
2204
2205 void SCREEN_OT_border_select(wmOperatorType *ot)
2206 {
2207         /* identifiers */
2208         ot->name= "Border select";
2209         ot->idname= "SCREEN_OT_border_select";
2210         
2211         /* api callbacks */
2212         ot->exec= border_select_do;
2213         ot->invoke= WM_border_select_invoke;
2214         ot->modal= WM_border_select_modal;
2215         
2216         ot->poll= ED_operator_areaactive;
2217         
2218         /* rna */
2219         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
2220         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
2221         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
2222         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
2223         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
2224
2225 }
2226 #endif
2227
2228 /* ****************************** render invoking ***************** */
2229
2230 /* set callbacks, exported to sequence render too. 
2231 Only call in foreground (UI) renders. */
2232
2233 /* returns biggest area that is not uv/image editor. Note that it uses buttons */
2234 /* window as the last possible alternative.                                                                        */
2235 static ScrArea *biggest_non_image_area(bContext *C)
2236 {
2237         bScreen *sc= CTX_wm_screen(C);
2238         ScrArea *sa, *big= NULL;
2239         int size, maxsize= 0, bwmaxsize= 0;
2240         short foundwin= 0;
2241         
2242         for(sa= sc->areabase.first; sa; sa= sa->next) {
2243                 if(sa->winx > 30 && sa->winy > 30) {
2244                         size= sa->winx*sa->winy;
2245                         if(sa->spacetype == SPACE_BUTS) {
2246                                 if(foundwin == 0 && size > bwmaxsize) {
2247                                         bwmaxsize= size;
2248                                         big= sa;        
2249                                 }
2250                         }
2251                         else if(sa->spacetype != SPACE_IMAGE && size > maxsize) {
2252                                 maxsize= size;
2253                                 big= sa;
2254                                 foundwin= 1;
2255                         }
2256                 }
2257         }
2258         
2259         return big;
2260 }
2261
2262 static ScrArea *biggest_area(bContext *C)
2263 {
2264         bScreen *sc= CTX_wm_screen(C);
2265         ScrArea *sa, *big= NULL;
2266         int size, maxsize= 0;
2267         
2268         for(sa= sc->areabase.first; sa; sa= sa->next) {
2269                 size= sa->winx*sa->winy;
2270                 if(size > maxsize) {
2271                         maxsize= size;
2272                         big= sa;
2273                 }
2274         }
2275         return big;
2276 }
2277
2278
2279 static ScrArea *find_area_showing_r_result(bContext *C)
2280 {
2281         bScreen *sc= CTX_wm_screen(C);
2282         ScrArea *sa;
2283         SpaceImage *sima;
2284         
2285         /* find an imagewindow showing render result */
2286         for(sa=sc->areabase.first; sa; sa= sa->next) {
2287                 if(sa->spacetype==SPACE_IMAGE) {
2288                         sima= sa->spacedata.first;
2289                         if(sima->image && sima->image->type==IMA_TYPE_R_RESULT)
2290                                 break;
2291                 }
2292         }
2293         return sa;
2294 }
2295
2296 static void screen_set_image_output(bContext *C)
2297 {
2298         ScrArea *sa;
2299         SpaceImage *sima;
2300         
2301         sa= find_area_showing_r_result(C);
2302         
2303         if(sa==NULL) {
2304                 /* find largest open non-image area */
2305                 sa= biggest_non_image_area(C);
2306                 if(sa) {
2307                         ED_area_newspace(C, sa, SPACE_IMAGE);
2308                         sima= sa->spacedata.first;
2309                         
2310                         /* makes ESC go back to prev space */
2311                         sima->flag |= SI_PREVSPACE;
2312                 }
2313                 else {
2314                         /* use any area of decent size */
2315                         sa= biggest_area(C);
2316                         if(sa->spacetype!=SPACE_IMAGE) {
2317                                 // XXX newspace(sa, SPACE_IMAGE);
2318                                 sima= sa->spacedata.first;
2319                                 
2320                                 /* makes ESC go back to prev space */
2321                                 sima->flag |= SI_PREVSPACE;
2322                         }
2323                 }
2324         }
2325         
2326         sima= sa->spacedata.first;
2327         
2328         /* get the correct image, and scale it */
2329         sima->image= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
2330         
2331         if(G.displaymode==2) { // XXX
2332                 if(sa->full==0) {
2333                         sima->flag |= SI_FULLWINDOW;
2334                         
2335                         ed_screen_fullarea(C, sa);
2336                 }
2337         }
2338         
2339 }
2340
2341 /* executes blocking render */
2342 static int screen_render_exec(bContext *C, wmOperator *op)
2343 {
2344         Scene *scene= CTX_data_scene(C);
2345         Render *re= RE_GetRender(scene->id.name);
2346         
2347         if(re==NULL) {
2348                 re= RE_NewRender(scene->id.name);
2349         }
2350         RE_test_break_cb(re, NULL, (int (*)(void *)) blender_test_break);
2351         
2352         if(RNA_boolean_get(op->ptr, "anim"))
2353                 RE_BlenderAnim(re, scene, scene->r.sfra, scene->r.efra, scene->frame_step);
2354         else
2355                 RE_BlenderFrame(re, scene, scene->r.cfra);
2356         
2357         // no redraw needed, we leave state as we entered it
2358         ED_update_for_newframe(C, 1);
2359         
2360         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
2361
2362         return OPERATOR_FINISHED;
2363 }
2364
2365 typedef struct RenderJob {
2366         Scene *scene;
2367         Render *re;
2368         wmWindow *win;
2369         int anim;
2370         Image *image;
2371         ImageUser iuser;
2372         short *stop;
2373         short *do_update;
2374 } RenderJob;
2375
2376 static void render_freejob(void *rjv)
2377 {
2378         RenderJob *rj= rjv;
2379         
2380         MEM_freeN(rj);
2381 }
2382
2383 /* called inside thread! */
2384 static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrect)
2385 {
2386         RenderJob *rj= rjv;
2387         ImBuf *ibuf;
2388         float x1, y1, *rectf= NULL;
2389         int ymin, ymax, xmin, xmax;
2390         int rymin, rxmin;
2391         char *rectc;
2392         
2393         ibuf= BKE_image_get_ibuf(rj->image, &rj->iuser);
2394         if(ibuf==NULL) return;
2395
2396         /* if renrect argument, we only refresh scanlines */
2397         if(renrect) {
2398                 /* if ymax==recty, rendering of layer is ready, we should not draw, other things happen... */
2399                 if(rr->renlay==NULL || renrect->ymax>=rr->recty)
2400                         return;
2401                 
2402                 /* xmin here is first subrect x coord, xmax defines subrect width */
2403                 xmin = renrect->xmin + rr->crop;
2404                 xmax = renrect->xmax - xmin - rr->crop;
2405                 if (xmax<2) return;
2406                 
2407                 ymin= renrect->ymin + rr->crop;
2408                 ymax= renrect->ymax - ymin - rr->crop;
2409                 if(ymax<2)
2410                         return;
2411                 renrect->ymin= renrect->ymax;
2412                 
2413         }
2414         else {
2415                 xmin = ymin = rr->crop;
2416                 xmax = rr->rectx - 2*rr->crop;
2417                 ymax = rr->recty - 2*rr->crop;
2418         }
2419         
2420         /* xmin ymin is in tile coords. transform to ibuf */
2421         rxmin= rr->tilerect.xmin + xmin;
2422         if(rxmin >= ibuf->x) return;
2423         rymin= rr->tilerect.ymin + ymin;
2424         if(rymin >= ibuf->y) return;
2425         
2426         if(rxmin + xmax > ibuf->x)
2427                 xmax= ibuf->x - rxmin;
2428         if(rymin + ymax > ibuf->y)
2429                 ymax= ibuf->y - rymin;
2430         
2431         if(xmax < 1 || ymax < 1) return;
2432         
2433         /* find current float rect for display, first case is after composit... still weak */
2434         if(rr->rectf)
2435                 rectf= rr->rectf;
2436         else {
2437                 if(rr->rect32)
2438                         return;
2439                 else {
2440                         if(rr->renlay==NULL || rr->renlay->rectf==NULL) return;
2441                         rectf= rr->renlay->rectf;
2442                 }
2443         }
2444         if(rectf==NULL) return;
2445         
2446         rectf+= 4*(rr->rectx*ymin + xmin);
2447         rectc= (char *)(ibuf->rect + ibuf->x*rymin + rxmin);
2448
2449         for(y1= 0; y1<ymax; y1++) {
2450                 float *rf= rectf;
2451                 char *rc= rectc;
2452                 
2453                 /* XXX temp. because crop offset */
2454                 if( rectc >= (char *)(ibuf->rect)) {
2455                         for(x1= 0; x1<xmax; x1++, rf += 4, rc+=4) {
2456                                 rc[0]= FTOCHAR(rf[0]);
2457                                 rc[1]= FTOCHAR(rf[1]);
2458                                 rc[2]= FTOCHAR(rf[2]);
2459                                 rc[3]= FTOCHAR(rf[3]);
2460                         }
2461                 }
2462                 rectf += 4*rr->rectx;
2463                 rectc += 4*ibuf->x;
2464         }
2465         
2466         /* make jobs timer to send notifier */
2467         *(rj->do_update)= 1;
2468 }
2469
2470 static void render_startjob(void *rjv, short *stop, short *do_update)
2471 {
2472         RenderJob *rj= rjv;
2473         
2474         rj->stop= stop;
2475         rj->do_update= do_update;
2476         
2477         if(rj->anim)
2478                 RE_BlenderAnim(rj->re, rj->scene, rj->scene->r.sfra, rj->scene->r.efra, rj->scene->frame_step);
2479         else
2480                 RE_BlenderFrame(rj->re, rj->scene, rj->scene->r.cfra);
2481 }
2482
2483 /* called by render, check job 'stop' value or the global */
2484 static int render_breakjob(void *rjv)
2485 {
2486         RenderJob *rj= rjv;
2487         
2488         if(G.afbreek)
2489                 return 1;
2490         if(rj->stop && *(rj->stop))
2491                 return 1;
2492         return 0;
2493 }
2494
2495 /* catch esc */
2496 static int screen_render_modal(bContext *C, wmOperator *op, wmEvent *event)
2497 {
2498         /* no running blender, remove handler and pass through */
2499         if(0==WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C)))
2500            return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
2501         
2502         /* running render */
2503         switch (event->type) {
2504                 case ESCKEY:
2505                         return OPERATOR_RUNNING_MODAL;
2506                         break;
2507         }
2508         return OPERATOR_PASS_THROUGH;
2509 }
2510
2511 /* using context, starts job */
2512 static int screen_render_invoke(bContext *C, wmOperator *op, wmEvent *event)
2513 {
2514         /* new render clears all callbacks */
2515         Scene *scene= CTX_data_scene(C);
2516         Render *re;
2517         wmJob *steve;
2518         RenderJob *rj;
2519         Image *ima;
2520         
2521         /* only one job at a time */
2522         if(WM_jobs_test(CTX_wm_manager(C), scene))
2523                 return OPERATOR_CANCELLED;
2524         
2525         /* handle UI stuff */
2526         WM_cursor_wait(1);
2527
2528         /* flush multires changes (for sculpt) */
2529         multires_force_update(CTX_data_active_object(C));
2530         
2531         // get editmode results
2532         // store spare
2533         // get view3d layer, local layer, make this nice api call to render
2534         // store spare
2535         
2536         /* ensure at least 1 area shows result */
2537         screen_set_image_output(C);
2538
2539         /* job custom data */
2540         rj= MEM_callocN(sizeof(RenderJob), "render job");
2541         rj->scene= scene;
2542         rj->win= CTX_wm_window(C);
2543         rj->anim= RNA_boolean_get(op->ptr, "anim");
2544         rj->iuser.scene= scene;
2545         rj->iuser.ok= 1;
2546         
2547         /* setup job */
2548         steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene);
2549         WM_jobs_customdata(steve, rj, render_freejob);
2550         WM_jobs_timer(steve, 0.2, NC_SCENE|ND_RENDER_RESULT, 0);
2551         WM_jobs_callbacks(steve, render_startjob, NULL, NULL);
2552         
2553         /* get a render result image, and make sure it is empty */
2554         ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
2555         BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
2556         rj->image= ima;
2557         
2558         /* setup new render */
2559         re= RE_NewRender(scene->id.name);
2560         RE_test_break_cb(re, rj, render_breakjob);
2561         RE_display_draw_cb(re, rj, image_rect_update);
2562         rj->re= re;
2563         G.afbreek= 0;
2564         
2565         //      BKE_report in render!
2566         //      RE_error_cb(re, error_cb);
2567
2568         WM_jobs_start(steve);
2569         
2570         G.afbreek= 0;
2571         
2572         WM_cursor_wait(0);
2573         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
2574
2575         /* add modal handler for ESC */
2576         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
2577         
2578         return OPERATOR_RUNNING_MODAL;
2579 }
2580
2581
2582 /* contextual render, using current scene, view3d? */
2583 void SCREEN_OT_render(wmOperatorType *ot)
2584 {
2585         /* identifiers */
2586         ot->name= "Render";
2587         ot->idname= "SCREEN_OT_render";
2588         
2589         /* api callbacks */
2590         ot->invoke= screen_render_invoke;
2591         ot->modal= screen_render_modal;
2592         ot->exec= screen_render_exec;
2593         
2594         ot->poll= ED_operator_screenactive;
2595         
2596         RNA_def_int(ot->srna, "layers", 0, 0, INT_MAX, "Layers", "", 0, INT_MAX);
2597         RNA_def_boolean(ot->srna, "anim", 0, "Animation", "");
2598 }
2599
2600 /* *********************** cancel render viewer *************** */
2601
2602 static int render_view_cancel_exec(bContext *C, wmOperator *unused)
2603 {
2604         ScrArea *sa= CTX_wm_area(C);
2605         SpaceImage *sima= sa->spacedata.first;
2606         
2607         if(sima->flag & SI_PREVSPACE) {
2608                 sima->flag &= ~SI_PREVSPACE;
2609                 
2610                 if(sima->flag & SI_FULLWINDOW) {
2611                         sima->flag &= ~SI_FULLWINDOW;
2612                         ED_screen_full_prevspace(C);
2613                 }
2614                 else
2615                         ED_area_prevspace(C);
2616         }
2617         else if(sima->flag & SI_FULLWINDOW) {
2618                 sima->flag &= ~SI_FULLWINDOW;
2619                 ed_screen_fullarea(C, sa);
2620         }               
2621         
2622         return OPERATOR_FINISHED;
2623 }
2624
2625 void SCREEN_OT_render_view_cancel(struct wmOperatorType *ot)
2626 {
2627         /* identifiers */
2628         ot->name= "Cancel Render View";
2629         ot->idname= "SCREEN_OT_render_view_cancel";
2630         
2631         /* api callbacks */
2632         ot->exec= render_view_cancel_exec;
2633         ot->poll= ED_operator_image_active;
2634 }
2635
2636
2637 /* ****************  Assigning operatortypes to global list, adding handlers **************** */
2638
2639 /* called in spacetypes.c */
2640 void ED_operatortypes_screen(void)
2641 {
2642         /* generic UI stuff */
2643         WM_operatortype_append(SCREEN_OT_actionzone);
2644         WM_operatortype_append(SCREEN_OT_repeat_last);
2645         WM_operatortype_append(SCREEN_OT_repeat_history);
2646         WM_operatortype_append(SCREEN_OT_redo_last);
2647         
2648         /* screen tools */
2649         WM_operatortype_append(SCREEN_OT_area_move);
2650         WM_operatortype_append(SCREEN_OT_area_split);
2651         WM_operatortype_append(SCREEN_OT_area_join);
2652         WM_operatortype_append(SCREEN_OT_area_dupli);
2653         WM_operatortype_append(SCREEN_OT_area_swap);
2654         WM_operatortype_append(SCREEN_OT_region_split);
2655         WM_operatortype_append(SCREEN_OT_region_foursplit);
2656         WM_operatortype_append(SCREEN_OT_region_flip);
2657         WM_operatortype_append(SCREEN_OT_region_scale);
2658         WM_operatortype_append(SCREEN_OT_screen_set);
2659         WM_operatortype_append(SCREEN_OT_screen_full_area);
2660         WM_operatortype_append(SCREEN_OT_screenshot);
2661         WM_operatortype_append(SCREEN_OT_screencast);
2662         
2663         /*frame changes*/
2664         WM_operatortype_append(SCREEN_OT_frame_offset);
2665         WM_operatortype_append(SCREEN_OT_animation_step);
2666         WM_operatortype_append(SCREEN_OT_animation_play);
2667         
2668         /* render */
2669         WM_operatortype_append(SCREEN_OT_render);
2670         WM_operatortype_append(SCREEN_OT_render_view_cancel);
2671         
2672         /* tools shared by more space types */
2673         WM_operatortype_append(ED_OT_undo);
2674         WM_operatortype_append(ED_OT_redo);     
2675         
2676 }
2677
2678 /* called in spacetypes.c */
2679 void ED_keymap_screen(wmWindowManager *wm)
2680 {
2681         ListBase *keymap= WM_keymap_listbase(wm, "Screen", 0, 0);
2682         
2683         /* standard timers */
2684         WM_keymap_add_item(keymap, "SCREEN_OT_animation_step", TIMER0, KM_ANY, KM_ANY, 0);
2685         
2686         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "modifier", 0);
2687         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "modifier", 1);
2688         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "modifier", 2);
2689         
2690         /* screen tools */
2691         WM_keymap_verify_item(keymap, "SCREEN_OT_area_split", EVT_ACTIONZONE_AREA, 0, 0, 0);
2692         WM_keymap_verify_item(keymap, "SCREEN_OT_area_join", EVT_ACTIONZONE_AREA, 0, 0, 0);
2693         WM_keymap_verify_item(keymap, "SCREEN_OT_area_dupli", EVT_ACTIONZONE_AREA, 0, KM_SHIFT, 0);
2694         WM_keymap_verify_item(keymap, "SCREEN_OT_area_swap", EVT_ACTIONZONE_AREA, 0, KM_ALT, 0);
2695         WM_keymap_verify_item(keymap, "SCREEN_OT_region_scale", EVT_ACTIONZONE_REGION, 0, 0, 0);
2696                         /* area move after action zones */
2697         WM_keymap_verify_item(keymap, "SCREEN_OT_area_move", LEFTMOUSE, KM_PRESS, 0, 0);
2698         
2699         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", 1);
2700         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", -1);
2701         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", UPARROWKEY, KM_PRESS, KM_CTRL, 0);
2702         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", DOWNARROWKEY, KM_PRESS, KM_CTRL, 0);
2703         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", SPACEKEY, KM_PRESS, KM_CTRL, 0);
2704         WM_keymap_add_item(keymap, "SCREEN_OT_screenshot", F3KEY, KM_PRESS, KM_CTRL, 0);
2705         WM_keymap_add_item(keymap, "SCREEN_OT_screencast", F3KEY, KM_PRESS, KM_ALT, 0);
2706
2707          /* tests */
2708         WM_keymap_add_item(keymap, "SCREEN_OT_region_split", SKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
2709         WM_keymap_add_item(keymap, "SCREEN_OT_region_foursplit", SKEY, KM_PRESS, KM_CTRL|KM_ALT|KM_SHIFT, 0);
2710         
2711         WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_history", F3KEY, KM_PRESS, 0, 0);
2712         WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_last", F4KEY, KM_PRESS, 0, 0);
2713         WM_keymap_add_item(keymap, "SCREEN_OT_region_flip", F5KEY, KM_PRESS, 0, 0);
2714         WM_keymap_verify_item(keymap, "SCREEN_OT_redo_last", F6KEY, KM_PRESS, 0, 0);
2715         
2716         RNA_string_set(WM_keymap_add_item(keymap, "SCRIPT_OT_python_file_run", F7KEY, KM_PRESS, 0, 0)->ptr, "filename", "test.py");
2717         WM_keymap_verify_item(keymap, "SCRIPT_OT_python_run_ui_scripts", F8KEY, KM_PRESS, 0, 0);
2718
2719         /* files */
2720         WM_keymap_add_item(keymap, "FILE_OT_exec", RETKEY, KM_PRESS, 0, 0);
2721         WM_keymap_add_item(keymap, "FILE_OT_cancel", ESCKEY, KM_PRESS, 0, 0);
2722         
2723         /* undo */
2724         WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_CTRL, 0);
2725         WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_OSKEY, 0);
2726         WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
2727         WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_OSKEY, 0);
2728                                                   
2729         /* render */
2730         WM_keymap_add_item(keymap, "SCREEN_OT_render", F12KEY, KM_PRESS, 0, 0);
2731         WM_keymap_add_item(keymap, "SCREEN_OT_render_view_cancel", ESCKEY, KM_PRESS, 0, 0);
2732         
2733         /* frame offsets & play */
2734         keymap= WM_keymap_listbase(wm, "Frames", 0, 0);
2735         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", UPARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 10);
2736         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", DOWNARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -10);
2737         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", LEFTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -1);
2738         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", RIGHTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 1);
2739         WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", AKEY, KM_PRESS, KM_ALT, 0);
2740         
2741 }
2742