NLA SoC: Merge from 2.5
[blender.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                         scene->r.cfra += step;
2071                         wt->duration -= ((float)step)/FPS;
2072                 }
2073                 else
2074                         scene->r.cfra++;
2075                 
2076                 if (scene->r.psfra) {
2077                         if(scene->r.cfra > scene->r.pefra)
2078                                 scene->r.cfra= scene->r.psfra;
2079                 }
2080                 else {
2081                         if(scene->r.cfra > scene->r.efra)
2082                                 scene->r.cfra= scene->r.sfra;
2083                 }
2084
2085                 /* since we follow drawflags, we can't send notifier but tag regions ourselves */
2086                 ED_update_for_newframe(C, 1);
2087                 
2088                 for(sa= screen->areabase.first; sa; sa= sa->next) {
2089                         ARegion *ar;
2090                         for(ar= sa->regionbase.first; ar; ar= ar->next) {
2091                                 if(ar==sad->ar)
2092                                         ED_region_tag_redraw(ar);
2093                                 else
2094                                         if(match_region_with_redraws(sa->spacetype, ar->regiontype, sad->redraws))
2095                                                 ED_region_tag_redraw(ar);
2096                         }
2097                 }
2098                 
2099                 //WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
2100                 
2101                 return OPERATOR_FINISHED;
2102         }
2103         return OPERATOR_PASS_THROUGH;
2104 }
2105
2106 static void SCREEN_OT_animation_step(wmOperatorType *ot)
2107 {
2108         /* identifiers */
2109         ot->name= "Animation Step";
2110         ot->idname= "SCREEN_OT_animation_step";
2111         
2112         /* api callbacks */
2113         ot->invoke= screen_animation_step;
2114         
2115         ot->poll= ED_operator_screenactive;
2116         
2117 }
2118
2119 /* ****************** anim player, starts or ends timer ***************** */
2120
2121 /* toggle operator */
2122 static int screen_animation_play(bContext *C, wmOperator *op, wmEvent *event)
2123 {
2124         bScreen *screen= CTX_wm_screen(C);
2125         
2126         if(screen->animtimer) {
2127                 ED_screen_animation_timer(C, 0, 0);
2128         }
2129         else {
2130                 /* todo: RNA properties to define play types */
2131                 ED_screen_animation_timer(C, TIME_REGION|TIME_ALL_3D_WIN, 1);
2132                 
2133                 if(screen->animtimer) {
2134                         wmTimer *wt= screen->animtimer;
2135                         ScreenAnimData *sad= wt->customdata;
2136                         
2137                         sad->ar= CTX_wm_region(C);
2138                 }
2139         }
2140         
2141         return OPERATOR_FINISHED;
2142 }
2143
2144 void SCREEN_OT_animation_play(wmOperatorType *ot)
2145 {
2146         /* identifiers */
2147         ot->name= "Animation player";
2148         ot->idname= "SCREEN_OT_animation_play";
2149         
2150         /* api callbacks */
2151         ot->invoke= screen_animation_play;
2152         
2153         ot->poll= ED_operator_screenactive;
2154         
2155         
2156 }
2157
2158 /* ************** border select operator (template) ***************************** */
2159
2160 /* operator state vars used: (added by default WM callbacks)   
2161         xmin, ymin     
2162         xmax, ymax     
2163
2164         customdata: the wmGesture pointer
2165
2166 callbacks:
2167
2168         exec()  has to be filled in by user
2169
2170         invoke() default WM function
2171                          adds modal handler
2172
2173         modal() default WM function 
2174                         accept modal events while doing it, calls exec(), handles ESC and border drawing
2175         
2176         poll()  has to be filled in by user for context
2177 */
2178 #if 0
2179 static int border_select_do(bContext *C, wmOperator *op)
2180 {
2181         int event_type= RNA_int_get(op->ptr, "event_type");
2182         
2183         if(event_type==LEFTMOUSE)
2184                 printf("border select do select\n");
2185         else if(event_type==RIGHTMOUSE)
2186                 printf("border select deselect\n");
2187         else 
2188                 printf("border select do something\n");
2189         
2190         return 1;
2191 }
2192
2193 void SCREEN_OT_border_select(wmOperatorType *ot)
2194 {
2195         /* identifiers */
2196         ot->name= "Border select";
2197         ot->idname= "SCREEN_OT_border_select";
2198         
2199         /* api callbacks */
2200         ot->exec= border_select_do;
2201         ot->invoke= WM_border_select_invoke;
2202         ot->modal= WM_border_select_modal;
2203         
2204         ot->poll= ED_operator_areaactive;
2205         
2206         /* rna */
2207         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
2208         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
2209         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
2210         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
2211         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
2212
2213 }
2214 #endif
2215
2216 /* ****************************** render invoking ***************** */
2217
2218 /* set callbacks, exported to sequence render too. 
2219 Only call in foreground (UI) renders. */
2220
2221 /* returns biggest area that is not uv/image editor. Note that it uses buttons */
2222 /* window as the last possible alternative.                                                                        */
2223 static ScrArea *biggest_non_image_area(bContext *C)
2224 {
2225         bScreen *sc= CTX_wm_screen(C);
2226         ScrArea *sa, *big= NULL;
2227         int size, maxsize= 0, bwmaxsize= 0;
2228         short foundwin= 0;
2229         
2230         for(sa= sc->areabase.first; sa; sa= sa->next) {
2231                 if(sa->winx > 30 && sa->winy > 30) {
2232                         size= sa->winx*sa->winy;
2233                         if(sa->spacetype == SPACE_BUTS) {
2234                                 if(foundwin == 0 && size > bwmaxsize) {
2235                                         bwmaxsize= size;
2236                                         big= sa;        
2237                                 }
2238                         }
2239                         else if(sa->spacetype != SPACE_IMAGE && size > maxsize) {
2240                                 maxsize= size;
2241                                 big= sa;
2242                                 foundwin= 1;
2243                         }
2244                 }
2245         }
2246         
2247         return big;
2248 }
2249
2250 static ScrArea *biggest_area(bContext *C)
2251 {
2252         bScreen *sc= CTX_wm_screen(C);
2253         ScrArea *sa, *big= NULL;
2254         int size, maxsize= 0;
2255         
2256         for(sa= sc->areabase.first; sa; sa= sa->next) {
2257                 size= sa->winx*sa->winy;
2258                 if(size > maxsize) {
2259                         maxsize= size;
2260                         big= sa;
2261                 }
2262         }
2263         return big;
2264 }
2265
2266
2267 static ScrArea *find_area_showing_r_result(bContext *C)
2268 {
2269         bScreen *sc= CTX_wm_screen(C);
2270         ScrArea *sa;
2271         SpaceImage *sima;
2272         
2273         /* find an imagewindow showing render result */
2274         for(sa=sc->areabase.first; sa; sa= sa->next) {
2275                 if(sa->spacetype==SPACE_IMAGE) {
2276                         sima= sa->spacedata.first;
2277                         if(sima->image && sima->image->type==IMA_TYPE_R_RESULT)
2278                                 break;
2279                 }
2280         }
2281         return sa;
2282 }
2283
2284 static void screen_set_image_output(bContext *C)
2285 {
2286         ScrArea *sa;
2287         SpaceImage *sima;
2288         
2289         sa= find_area_showing_r_result(C);
2290         
2291         if(sa==NULL) {
2292                 /* find largest open non-image area */
2293                 sa= biggest_non_image_area(C);
2294                 if(sa) {
2295                         ED_area_newspace(C, sa, SPACE_IMAGE);
2296                         sima= sa->spacedata.first;
2297                         
2298                         /* makes ESC go back to prev space */
2299                         sima->flag |= SI_PREVSPACE;
2300                 }
2301                 else {
2302                         /* use any area of decent size */
2303                         sa= biggest_area(C);
2304                         if(sa->spacetype!=SPACE_IMAGE) {
2305                                 // XXX newspace(sa, SPACE_IMAGE);
2306                                 sima= sa->spacedata.first;
2307                                 
2308                                 /* makes ESC go back to prev space */
2309                                 sima->flag |= SI_PREVSPACE;
2310                         }
2311                 }
2312         }
2313         
2314         sima= sa->spacedata.first;
2315         
2316         /* get the correct image, and scale it */
2317         sima->image= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
2318         
2319         if(G.displaymode==2) { // XXX
2320                 if(sa->full==0) {
2321                         sima->flag |= SI_FULLWINDOW;
2322                         
2323                         ed_screen_fullarea(C, sa);
2324                 }
2325         }
2326         
2327 }
2328
2329 /* executes blocking render */
2330 static int screen_render_exec(bContext *C, wmOperator *op)
2331 {
2332         Scene *scene= CTX_data_scene(C);
2333         Render *re= RE_GetRender(scene->id.name);
2334         
2335         if(re==NULL) {
2336                 re= RE_NewRender(scene->id.name);
2337         }
2338         RE_test_break_cb(re, NULL, (int (*)(void *)) blender_test_break);
2339         
2340         if(RNA_boolean_get(op->ptr, "anim"))
2341                 RE_BlenderAnim(re, scene, scene->r.sfra, scene->r.efra, scene->frame_step);
2342         else
2343                 RE_BlenderFrame(re, scene, scene->r.cfra);
2344         
2345         // no redraw needed, we leave state as we entered it
2346         ED_update_for_newframe(C, 1);
2347         
2348         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
2349
2350         return OPERATOR_FINISHED;
2351 }
2352
2353 typedef struct RenderJob {
2354         Scene *scene;
2355         Render *re;
2356         wmWindow *win;
2357         int anim;
2358         Image *image;
2359         ImageUser iuser;
2360         short *stop;
2361         short *do_update;
2362 } RenderJob;
2363
2364 static void render_freejob(void *rjv)
2365 {
2366         RenderJob *rj= rjv;
2367         
2368         MEM_freeN(rj);
2369 }
2370
2371 /* called inside thread! */
2372 static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrect)
2373 {
2374         RenderJob *rj= rjv;
2375         ImBuf *ibuf;
2376         float x1, y1, *rectf= NULL;
2377         int ymin, ymax, xmin, xmax;
2378         int rymin, rxmin;
2379         char *rectc;
2380         
2381         ibuf= BKE_image_get_ibuf(rj->image, &rj->iuser);
2382         if(ibuf==NULL) return;
2383
2384         /* if renrect argument, we only refresh scanlines */
2385         if(renrect) {
2386                 /* if ymax==recty, rendering of layer is ready, we should not draw, other things happen... */
2387                 if(rr->renlay==NULL || renrect->ymax>=rr->recty)
2388                         return;
2389                 
2390                 /* xmin here is first subrect x coord, xmax defines subrect width */
2391                 xmin = renrect->xmin + rr->crop;
2392                 xmax = renrect->xmax - xmin - rr->crop;
2393                 if (xmax<2) return;
2394                 
2395                 ymin= renrect->ymin + rr->crop;
2396                 ymax= renrect->ymax - ymin - rr->crop;
2397                 if(ymax<2)
2398                         return;
2399                 renrect->ymin= renrect->ymax;
2400                 
2401         }
2402         else {
2403                 xmin = ymin = rr->crop;
2404                 xmax = rr->rectx - 2*rr->crop;
2405                 ymax = rr->recty - 2*rr->crop;
2406         }
2407         
2408         /* xmin ymin is in tile coords. transform to ibuf */
2409         rxmin= rr->tilerect.xmin + xmin;
2410         if(rxmin >= ibuf->x) return;
2411         rymin= rr->tilerect.ymin + ymin;
2412         if(rymin >= ibuf->y) return;
2413         
2414         if(rxmin + xmax > ibuf->x)
2415                 xmax= ibuf->x - rxmin;
2416         if(rymin + ymax > ibuf->y)
2417                 ymax= ibuf->y - rymin;
2418         
2419         if(xmax < 1 || ymax < 1) return;
2420         
2421         /* find current float rect for display, first case is after composit... still weak */
2422         if(rr->rectf)
2423                 rectf= rr->rectf;
2424         else {
2425                 if(rr->rect32)
2426                         return;
2427                 else {
2428                         if(rr->renlay==NULL || rr->renlay->rectf==NULL) return;
2429                         rectf= rr->renlay->rectf;
2430                 }
2431         }
2432         if(rectf==NULL) return;
2433         
2434         rectf+= 4*(rr->rectx*ymin + xmin);
2435         rectc= (char *)(ibuf->rect + ibuf->x*rymin + rxmin);
2436
2437         for(y1= 0; y1<ymax; y1++) {
2438                 float *rf= rectf;
2439                 char *rc= rectc;
2440                 
2441                 /* XXX temp. because crop offset */
2442                 if( rectc >= (char *)(ibuf->rect)) {
2443                         for(x1= 0; x1<xmax; x1++, rf += 4, rc+=4) {
2444                                 rc[0]= FTOCHAR(rf[0]);
2445                                 rc[1]= FTOCHAR(rf[1]);
2446                                 rc[2]= FTOCHAR(rf[2]);
2447                                 rc[3]= FTOCHAR(rf[3]);
2448                         }
2449                 }
2450                 rectf += 4*rr->rectx;
2451                 rectc += 4*ibuf->x;
2452         }
2453         
2454         /* make jobs timer to send notifier */
2455         *(rj->do_update)= 1;
2456 }
2457
2458 static void render_startjob(void *rjv, short *stop, short *do_update)
2459 {
2460         RenderJob *rj= rjv;
2461         
2462         rj->stop= stop;
2463         rj->do_update= do_update;
2464         
2465         if(rj->anim)
2466                 RE_BlenderAnim(rj->re, rj->scene, rj->scene->r.sfra, rj->scene->r.efra, rj->scene->frame_step);
2467         else
2468                 RE_BlenderFrame(rj->re, rj->scene, rj->scene->r.cfra);
2469 }
2470
2471 /* called by render, check job 'stop' value or the global */
2472 static int render_breakjob(void *rjv)
2473 {
2474         RenderJob *rj= rjv;
2475         
2476         if(G.afbreek)
2477                 return 1;
2478         if(rj->stop && *(rj->stop))
2479                 return 1;
2480         return 0;
2481 }
2482
2483 /* catch esc */
2484 static int screen_render_modal(bContext *C, wmOperator *op, wmEvent *event)
2485 {
2486         /* no running blender, remove handler and pass through */
2487         if(0==WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C)))
2488            return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
2489         
2490         /* running render */
2491         switch (event->type) {
2492                 case ESCKEY:
2493                         return OPERATOR_RUNNING_MODAL;
2494                         break;
2495         }
2496         return OPERATOR_PASS_THROUGH;
2497 }
2498
2499 /* using context, starts job */
2500 static int screen_render_invoke(bContext *C, wmOperator *op, wmEvent *event)
2501 {
2502         /* new render clears all callbacks */
2503         Scene *scene= CTX_data_scene(C);
2504         Render *re;
2505         wmJob *steve;
2506         RenderJob *rj;
2507         Image *ima;
2508         
2509         /* only one job at a time */
2510         if(WM_jobs_test(CTX_wm_manager(C), scene))
2511                 return OPERATOR_CANCELLED;
2512         
2513         /* handle UI stuff */
2514         WM_cursor_wait(1);
2515
2516         /* flush multires changes (for sculpt) */
2517         multires_force_update(CTX_data_active_object(C));
2518         
2519         /* get editmode results */
2520         ED_object_exit_editmode(C, 0);  /* 0 = does not exit editmode */
2521         
2522         // store spare
2523         // get view3d layer, local layer, make this nice api call to render
2524         // store spare
2525         
2526         /* ensure at least 1 area shows result */
2527         screen_set_image_output(C);
2528
2529         /* job custom data */
2530         rj= MEM_callocN(sizeof(RenderJob), "render job");
2531         rj->scene= scene;
2532         rj->win= CTX_wm_window(C);
2533         rj->anim= RNA_boolean_get(op->ptr, "anim");
2534         rj->iuser.scene= scene;
2535         rj->iuser.ok= 1;
2536         
2537         /* setup job */
2538         steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene);
2539         WM_jobs_customdata(steve, rj, render_freejob);
2540         WM_jobs_timer(steve, 0.2, NC_SCENE|ND_RENDER_RESULT, 0);
2541         WM_jobs_callbacks(steve, render_startjob, NULL, NULL);
2542         
2543         /* get a render result image, and make sure it is empty */
2544         ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
2545         BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
2546         rj->image= ima;
2547         
2548         /* setup new render */
2549         re= RE_NewRender(scene->id.name);
2550         RE_test_break_cb(re, rj, render_breakjob);
2551         RE_display_draw_cb(re, rj, image_rect_update);
2552         rj->re= re;
2553         G.afbreek= 0;
2554         
2555         //      BKE_report in render!
2556         //      RE_error_cb(re, error_cb);
2557
2558         WM_jobs_start(CTX_wm_manager(C), steve);
2559         
2560         G.afbreek= 0;
2561         
2562         WM_cursor_wait(0);
2563         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
2564
2565         /* add modal handler for ESC */
2566         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
2567         
2568         return OPERATOR_RUNNING_MODAL;
2569 }
2570
2571
2572 /* contextual render, using current scene, view3d? */
2573 void SCREEN_OT_render(wmOperatorType *ot)
2574 {
2575         /* identifiers */
2576         ot->name= "Render";
2577         ot->idname= "SCREEN_OT_render";
2578         
2579         /* api callbacks */
2580         ot->invoke= screen_render_invoke;
2581         ot->modal= screen_render_modal;
2582         ot->exec= screen_render_exec;
2583         
2584         ot->poll= ED_operator_screenactive;
2585         
2586         RNA_def_int(ot->srna, "layers", 0, 0, INT_MAX, "Layers", "", 0, INT_MAX);
2587         RNA_def_boolean(ot->srna, "anim", 0, "Animation", "");
2588 }
2589
2590 /* *********************** cancel render viewer *************** */
2591
2592 static int render_view_cancel_exec(bContext *C, wmOperator *unused)
2593 {
2594         ScrArea *sa= CTX_wm_area(C);
2595         SpaceImage *sima= sa->spacedata.first;
2596         
2597         if(sima->flag & SI_PREVSPACE) {
2598                 sima->flag &= ~SI_PREVSPACE;
2599                 
2600                 if(sima->flag & SI_FULLWINDOW) {
2601                         sima->flag &= ~SI_FULLWINDOW;
2602                         ED_screen_full_prevspace(C);
2603                 }
2604                 else
2605                         ED_area_prevspace(C);
2606         }
2607         else if(sima->flag & SI_FULLWINDOW) {
2608                 sima->flag &= ~SI_FULLWINDOW;
2609                 ed_screen_fullarea(C, sa);
2610         }               
2611         
2612         return OPERATOR_FINISHED;
2613 }
2614
2615 void SCREEN_OT_render_view_cancel(struct wmOperatorType *ot)
2616 {
2617         /* identifiers */
2618         ot->name= "Cancel Render View";
2619         ot->idname= "SCREEN_OT_render_view_cancel";
2620         
2621         /* api callbacks */
2622         ot->exec= render_view_cancel_exec;
2623         ot->poll= ED_operator_image_active;
2624 }
2625
2626
2627 /* ****************  Assigning operatortypes to global list, adding handlers **************** */
2628
2629 /* called in spacetypes.c */
2630 void ED_operatortypes_screen(void)
2631 {
2632         /* generic UI stuff */
2633         WM_operatortype_append(SCREEN_OT_actionzone);
2634         WM_operatortype_append(SCREEN_OT_repeat_last);
2635         WM_operatortype_append(SCREEN_OT_repeat_history);
2636         WM_operatortype_append(SCREEN_OT_redo_last);
2637         
2638         /* screen tools */
2639         WM_operatortype_append(SCREEN_OT_area_move);
2640         WM_operatortype_append(SCREEN_OT_area_split);
2641         WM_operatortype_append(SCREEN_OT_area_join);
2642         WM_operatortype_append(SCREEN_OT_area_dupli);
2643         WM_operatortype_append(SCREEN_OT_area_swap);
2644         WM_operatortype_append(SCREEN_OT_region_split);
2645         WM_operatortype_append(SCREEN_OT_region_foursplit);
2646         WM_operatortype_append(SCREEN_OT_region_flip);
2647         WM_operatortype_append(SCREEN_OT_region_scale);
2648         WM_operatortype_append(SCREEN_OT_screen_set);
2649         WM_operatortype_append(SCREEN_OT_screen_full_area);
2650         WM_operatortype_append(SCREEN_OT_screenshot);
2651         WM_operatortype_append(SCREEN_OT_screencast);
2652         
2653         /*frame changes*/
2654         WM_operatortype_append(SCREEN_OT_frame_offset);
2655         WM_operatortype_append(SCREEN_OT_animation_step);
2656         WM_operatortype_append(SCREEN_OT_animation_play);
2657         
2658         /* render */
2659         WM_operatortype_append(SCREEN_OT_render);
2660         WM_operatortype_append(SCREEN_OT_render_view_cancel);
2661         
2662         /* tools shared by more space types */
2663         WM_operatortype_append(ED_OT_undo);
2664         WM_operatortype_append(ED_OT_redo);     
2665         
2666 }
2667
2668 /* called in spacetypes.c */
2669 void ED_keymap_screen(wmWindowManager *wm)
2670 {
2671         ListBase *keymap= WM_keymap_listbase(wm, "Screen", 0, 0);
2672         
2673         /* standard timers */
2674         WM_keymap_add_item(keymap, "SCREEN_OT_animation_step", TIMER0, KM_ANY, KM_ANY, 0);
2675         
2676         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "modifier", 0);
2677         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "modifier", 1);
2678         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "modifier", 2);
2679         
2680         /* screen tools */
2681         WM_keymap_verify_item(keymap, "SCREEN_OT_area_split", EVT_ACTIONZONE_AREA, 0, 0, 0);
2682         WM_keymap_verify_item(keymap, "SCREEN_OT_area_join", EVT_ACTIONZONE_AREA, 0, 0, 0);
2683         WM_keymap_verify_item(keymap, "SCREEN_OT_area_dupli", EVT_ACTIONZONE_AREA, 0, KM_SHIFT, 0);
2684         WM_keymap_verify_item(keymap, "SCREEN_OT_area_swap", EVT_ACTIONZONE_AREA, 0, KM_ALT, 0);
2685         WM_keymap_verify_item(keymap, "SCREEN_OT_region_scale", EVT_ACTIONZONE_REGION, 0, 0, 0);
2686                         /* area move after action zones */
2687         WM_keymap_verify_item(keymap, "SCREEN_OT_area_move", LEFTMOUSE, KM_PRESS, 0, 0);
2688         
2689         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", 1);
2690         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", -1);
2691         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", UPARROWKEY, KM_PRESS, KM_CTRL, 0);
2692         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", DOWNARROWKEY, KM_PRESS, KM_CTRL, 0);
2693         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", SPACEKEY, KM_PRESS, KM_CTRL, 0);
2694         WM_keymap_add_item(keymap, "SCREEN_OT_screenshot", F3KEY, KM_PRESS, KM_CTRL, 0);
2695         WM_keymap_add_item(keymap, "SCREEN_OT_screencast", F3KEY, KM_PRESS, KM_ALT, 0);
2696
2697          /* tests */
2698         WM_keymap_add_item(keymap, "SCREEN_OT_region_split", SKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
2699         WM_keymap_add_item(keymap, "SCREEN_OT_region_foursplit", SKEY, KM_PRESS, KM_CTRL|KM_ALT|KM_SHIFT, 0);
2700         
2701         WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_history", F3KEY, KM_PRESS, 0, 0);
2702         WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_last", F4KEY, KM_PRESS, 0, 0);
2703         WM_keymap_add_item(keymap, "SCREEN_OT_region_flip", F5KEY, KM_PRESS, 0, 0);
2704         WM_keymap_verify_item(keymap, "SCREEN_OT_redo_last", F6KEY, KM_PRESS, 0, 0);
2705         
2706         RNA_string_set(WM_keymap_add_item(keymap, "SCRIPT_OT_python_file_run", F7KEY, KM_PRESS, 0, 0)->ptr, "filename", "test.py");
2707         WM_keymap_verify_item(keymap, "SCRIPT_OT_python_run_ui_scripts", F8KEY, KM_PRESS, 0, 0);
2708
2709         /* files */
2710         WM_keymap_add_item(keymap, "FILE_OT_exec", RETKEY, KM_PRESS, 0, 0);
2711         WM_keymap_add_item(keymap, "FILE_OT_cancel", ESCKEY, KM_PRESS, 0, 0);
2712         
2713         /* undo */
2714         WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_CTRL, 0);
2715         WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_OSKEY, 0);
2716         WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
2717         WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_OSKEY, 0);
2718                                                   
2719         /* render */
2720         WM_keymap_add_item(keymap, "SCREEN_OT_render", F12KEY, KM_PRESS, 0, 0);
2721         WM_keymap_add_item(keymap, "SCREEN_OT_render_view_cancel", ESCKEY, KM_PRESS, 0, 0);
2722         
2723         /* frame offsets & play */
2724         keymap= WM_keymap_listbase(wm, "Frames", 0, 0);
2725         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", UPARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 10);
2726         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", DOWNARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -10);
2727         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", LEFTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -1);
2728         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", RIGHTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 1);
2729         WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", AKEY, KM_PRESS, KM_ALT, 0);
2730         
2731 }
2732