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